hello kity

期待您的批阅,由于写解题报告时 不一定考虑的很周到,所以如果您有什么不懂的地方,请您留言,然而一天之内我肯定会看见您信息,再对代码注释详细,让您更好的阅读

分类

最新评论

最新留言

链接

RSS

计数器
224243

功能

ZOJ (3497 Mistwald 关于矩阵求点直接连通的问题)
spoiler
posted @ 2011年4月29日 15:48
in 十个利用矩阵乘法解决的经典题目
, 2713 阅读
题目大意:给你一个N*M 的矩阵, 矩阵里的每个点代表一个全送阵, 代表当前点可以全送到4个点,你的出发点是(1,1);要到达的点是(n,m),这里要注意的是,一旦任何点到了(n,m)点之后 就会被全送出去,离开整个地图,所以这里算是一个陷阱,您要把(n,m)点能够到达的点,全部置0,(”0“代表他不能到达某个点)
题目分析:
这里是Maxtrix67 大牛总结的 第八个矩阵的经典应用:
给定一个有向图,问从A点恰好走k步(允许重复经过边)到达B点的方案数mod p的值
把 给定的图转为邻接矩阵,即A(i,j)=1当且仅当存在一条边i->j。令C=A*A,那么C(i,j)=ΣA(i,k)*A(k,j),实际上就 等于从点i到点j恰好经过2条边的路径数(枚举k为中转点)。类似地,C*A的第i行第j列就表示从i到j经过3条边的路径数。同理,如果要求经过k步的 路径数,我们只需要二分求出A^k即可;
题目让我们求的是他们是否连通,这里只需用1与0带入即可,
我们这里在乘的过程不是求和,而是用到“与”操作,因为我们要得出的结果不是路径数,而是 是否能经过K步到达该点~
代码+部分注释:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | # include <iostream> # include <cstdio> # include <cstring> using namespace std; struct M { int s[ 30 ][ 30 ]; }; struct M unit; int n; struct M multiply(struct M a,struct M b){ struct M c; for ( int i= 1 ;i<=n;i++) for ( int j= 1 ;j<=n;j++){ c.s[i][j]= 0 ; for ( int k= 1 ;k<=n;k++) //:注意下面这个操作,是“|”而不是“+”这里是求是否能到达 //而不是求 到达的路径数目! c.s[i][j]=(c.s[i][j]|a.s[i][k]*b.s[k][j]); } return c; } struct M paw(struct M a, int t){ struct M ans=unit; struct M b=a; while (t){ if (t% 2 == 1 ) ans=multiply(ans,b); b=multiply(b,b); t/= 2 ; } return ans; } int main(){ struct M a; memset(unit.s, 0 ,sizeof(unit.s)); char str[ 100 ]; int num[ 10 ]; for ( int i= 1 ;i<= 30 ;i++) unit.s[i][i]= 1 ; int h,z,p,cas,t; int s,e,i,j,k; scanf( "%d" ,&cas); while (cas--){ memset(a.s, 0 ,sizeof(a.s)); scanf( "%d %d" ,&h,&z); n=h*z; for (i= 1 ;i<=h;i++) for (j= 1 ;j<=z;j++){ scanf( "%s" ,str); sscanf(str, "((%d,%d),(%d,%d),(%d,%d),(%d,%d))" ,&num[ 1 ],&num[ 2 ],&num[ 3 ],&num[ 4 ],&num[ 5 ],&num[ 6 ],&num[ 7 ],&num[ 8 ]); s=(i- 1 )*z+j; for (k= 1 ;k<= 8 ;k+= 2 ){ e=(num[k]- 1 )*z+num[k+ 1 ]; a.s[s][e]= 1 ; } } //:转换成邻接矩阵后,a.s[n][]就是 //代表原来地图里的[n][m]点与其他点的链接状态 //因为题意说,凡是到了[n][m]点之后,就会马上 //全送出去,离开这个地图,所以我们要把[n][m]到其他点的 //状态值都赋为0! for (i= 1 ;i<=n;i++) a.s[n][i]= 0 ; scanf( "%d" ,&p); while (p--){ scanf( "%d" ,&t); struct M c=paw(a,t); if (c.s[ 1 ][n]== 0 ) printf( "False\n" ); else { int x; for (x= 1 ;x<=n;x++){ if (c.s[ 1 ][x]== 1 ) break ; } if (n==x) printf( "True\n" ); else printf( "Maybe\n" ); } } printf( "\n" ); } } |