矩阵十题(4)

经典题目4 VOJ1049

题目链接:https://vijos.org/p/1049

题目大意:顺次给出m个置换,反复使用这m个置换对初始序列进行操作,问k次置换后的序列。m<=10, k<2^31。
首先将这m个置换“合并”起来(算出这m个置换的乘积),然后接下来我们需要执行这个置换k/m次(取整,若有余数则剩下几步模拟即可)。注意任意一个置换都可以表示成矩阵的形式。例如,将1 2 3 4置换为3 1 2 4,相当于下面的矩阵乘法:

置换k/m次就相当于在前面乘以k/m个这样的矩阵。我们可以二分计算出该矩阵的k/m次方,再乘以初始序列即可。做出来了别忙着高兴,得意之时就是你灭亡之日,别忘了最后可能还有几个置换需要模拟。

注意:这m个置换对应的矩阵相乘的时候必须左乘

代码如下:

 1 #include<stdio.h>
 2 #include<string.h>
 3 #define N 110
 4 struct Matrix
 5 {
 6     int a[N][N];
 7 }origin,res,tmp,A,B,ans;
 8 int n;
 9 int op[N][N];
10 Matrix mul(Matrix x,Matrix y)
11 {
12     int i,j,k;
13     memset(tmp.a,0,sizeof(tmp.a));
14     for(i=1;i<=n;i++)
15         for(j=1;j<=n;j++)
16             for(k=1;k<=n;k++)
17                 tmp.a[i][j]+=x.a[i][k]*y.a[k][j];
18     return tmp;
19 }
20 Matrix quickpow(Matrix B,int k)
21 {
22     int i;
23     memset(res.a,0,sizeof(res.a));
24     for(i=1;i<=n;i++)
25         res.a[i][i]=1;
26     while(k)
27     {
28         if(k&1)
29             res=mul(res,B);
30         B=mul(B,B);
31         k>>=1;
32     }
33     return res;
34 }
35 void print(Matrix B)
36 {
37     int i,j;
38     for(i=1;i<=n;i++)
39     {
40         for(j=1;j<=n;j++)
41             printf("%d ",B.a[i][j]);
42         printf("\n");
43     }
44     printf("+++++++++\n");
45 }
46 int main()
47 {
48     int m,i,k,j;
49     while(scanf("%d%d%d",&n,&m,&k)!=EOF)
50     {
51         memset(B.a,0,sizeof(B.a));
52         for(i=1;i<=n;i++)
53             B.a[i][i]=1;
54         for(i=1;i<=m;i++)
55         {
56             for(j=1;j<=n;j++)
57                 scanf("%d",&op[i][j]);
58             memset(A.a,0,sizeof(A.a));   //置换所对应的矩阵
59             for(j=1;j<=n;j++)
60                 A.a[j][op[i][j]]=1;
61             B=mul(A,B);       //左乘
62         //    print(B);
63         }
64         res=quickpow(B,k/m);   //执行k/m次
65         memset(origin.a,0,sizeof(origin.a));
66         for(i=1;i<=n;i++)   
67             origin.a[i][1]=i;
68         ans=mul(res,origin);   //乘以初始矩阵
69         if(k%m)        //将剩余的几步模拟
70         {
71             for(i=1;i<=k%m;i++)
72             {
73                 memset(A.a,0,sizeof(A.a));
74                 for(j=1;j<=n;j++)
75                     A.a[j][op[i][j]]=1;
76                 ans=mul(A,ans);
77             }
78         }
79         for(i=1;i<=n;i++)
80         {
81             printf("%d",ans.a[i][1]);
82             if(i<n)
83                 printf(" ");
84         }
85         printf("\n");
86     }
87     return 0;
88 }
View Code

hdu  2371  Decode the Strings

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2371

题目大意:给出n 和m,给出n个数,代表一个置换,接着一个字符串s,s经过m次置换后变成另一个字符串,

现在给出经过m次置换后的字符串,输出原始字符串s

比如:5 3

        2 3 1 5 4

        hello

需经过3次置换,则"hello" -> "elhol" -> "lhelo" -> "helol"

思路:将置换规则取反(将p[i]位置上的数num[i]变成p[num[i]]上的数,例如,num:  2 3 1 5 4  变成  num:  3 1 2 5 4

                                                                                                         p: 1 2 3 4 5               p:  1 2 3 4 5  )

然后将m次置换合并起来,即算出这m个置换的乘积(即origin^m),然后乘以初始序列[1 2 3 4 ....n],然后输出对应位置的字符即可。

注意任意一个置换都可以表示成矩阵的形式。例如,将1 2 3 4置换为3 1 2 4,相当于下面的矩阵乘法:

m次置换就相当于前面乘以m个这样的矩阵,用矩阵快速幂即可。

代码如下:

 1 #include<stdio.h>
 2 #include<string.h>
 3 #define N 100
 4 struct Matrix
 5 {
 6     int a[N][N];
 7 }res,tmp,origin,A,ans;
 8 int n;
 9 int p[N],num[N];
10 char s[N];
11 Matrix mul(Matrix x,Matrix y)
12 {
13     int i,j,k;
14     memset(tmp.a,0,sizeof(tmp.a));
15     for(i=1;i<=n;i++)
16         for(j=1;j<=n;j++)
17             for(k=1;k<=n;k++)
18                 tmp.a[i][j]+=x.a[i][k]*y.a[k][j];
19     return tmp;
20 }
21 void quickpow(int k)  //矩阵快速幂
22 {
23     int i;
24     memset(res.a,0,sizeof(res.a));
25     for(i=1;i<=n;i++)
26         res.a[i][i]=1;
27     while(k)
28     {
29         if(k&1)
30             res=mul(res,origin);
31         origin=mul(origin,origin);
32         k>>=1;
33     }
34 }
35 
36 int main()
37 {
38     int m,i;
39     while(scanf("%d%d",&n,&m)!=EOF)
40     {
41         if(n==0&&m==0)
42             break;
43         for(i=1;i<=n;i++)
44             scanf("%d",&num[i]);
45         for(i=1;i<=n;i++)   //将置换取反
46             p[num[i]]=i;
47         memset(origin.a,0,sizeof(origin.a));  //将置换用矩阵表示
48         for(i=1;i<=n;i++)
49             origin.a[i][p[i]]=1;
50         getchar();
51         gets(s);
52         quickpow(m);   //乘以m次这样的矩阵
53         memset(A.a,0,sizeof(A.a));  //原始序列[1 2 3 4 5 ...n]
54         for(i=1;i<=n;i++)
55             A.a[i][1]=i;
56         ans=mul(res,A);   //与原始序列相乘
57         for(i=1;i<=n;i++)
58             printf("%c",s[ans.a[i][1]-1]);
59           //  printf("%d ",ans.a[i][1]);
60         printf("\n");
61     }
62     return 0;
63 }
View Code
原文地址:https://www.cnblogs.com/frog112111/p/3089358.html