首页 > 代码库 > 矩阵经典题目四:送给圣诞夜的礼品(使用m个置换实现对序列的转变)

矩阵经典题目四:送给圣诞夜的礼品(使用m个置换实现对序列的转变)

https://vijos.org/p/1049


给出一个序列,含n个数。然后是m个置换,求对初始序列依次进行k次置换,求最后的序列。


先看一个置换,把置换表示成矩阵的形式,然后将m个置换乘起来。那么初始序列首先执行这个置换k/m次,然后顺次执行前k%m个置换,最后乘上初始矩阵。

最后注意矩阵乘法的顺序,A*B != B*A。


#include <stdio.h>
#include <iostream>
#include <map>
#include <set>
#include <list>
#include <stack>
#include <vector>
#include <math.h>
#include <string.h>
#include <queue>
#include <string>
#include <stdlib.h>
#include <algorithm>
#define LL long long
#define _LL __int64
#define eps 1e-12
#define PI acos(-1.0)
#define C 240
#define S 20
using namespace std;

const int maxn = 110;

struct matrix
{
    int mat[maxn][maxn];
    int n,m;
    void init()
    {
        memset(mat,0,sizeof(mat));
        for(int i = 1; i <= 105; i++)
        {
            mat[i][i] = 1;
        }
    }
}M[11]; //将每一个置换表示出来。

int n,m;

matrix mul(matrix a, matrix b)
{
    matrix ans;
    memset(ans.mat,0,sizeof(ans.mat));
    ans.n = a.n;
    ans.m = b.m;
    for(int i = 1; i <= a.n ; i++)
    {
        for(int k = 1; k <= a.m; k++)
        {
            if(a.mat[i][k] == 0) continue;
            for(int j = 1; j <= b.m; j++)
                ans.mat[i][j] += a.mat[i][k]*b.mat[k][j];
        }
    }
    return ans;
}

matrix pow(matrix a, int n)
{
    matrix ans;
    ans.n = a.n;
    ans.m = a.m;
    ans.init();

    while(n)
    {
        if(n&1)
            ans = mul(ans,a);
        a = mul(a,a);
        n >>= 1;
    }
    return ans;
}

int main()
{
    int num,k,z;
    while(~scanf("%d %d %d",&n,&m,&k))
    {
        matrix a,b;
        a.init();
        a.m = a.n = n;
        b.n = n;
        b.m = 1;
        for(int i = 1; i <= n; i++)
            b.mat[i][1] = i;

        for(int i = 1; i <= m; i++)
        {
            memset(M[i].mat,0,sizeof(M[i].mat));
            M[i].m = M[i].n = n;
            for(int j = 1; j <= n; j++)
            {
                scanf("%d",&num);
                M[i].mat[j][num] = 1;
            }
            a = mul(M[i],a); //注意相乘的顺序 
        }

        z = k/m;
        k = k%m;

        a = pow(a,z);
        for(int i = 1; i <= k; i++)
            a = mul(M[i],a);//注意相乘的顺序
        a = mul(a,b);
        for(int i = 1; i <= n; i++)
        {
            printf("%d",a.mat[i][1]);
            if(i == n)
                printf("\n");
            else printf(" ");
        }
    }
    return 0;
}