原以为是用搜索做的题,想了好久都无法想到一个高效正确的解法。
后面发现竟然这就是矩阵的应用! 碉堡!
给定一个有向图,问从A点恰好走k步(允许重复经过边)到达B点的方案数mod p的值 ——选自matrix67
把给定的图转为邻接矩阵,即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即可。
#include <iostream> #include <string.h> #include <stdio.h> #include <algorithm> using namespace std; int n,m; bool g[33][33]; int x[10],y[10]; bool tg[33][33]; void mul(bool s[33][33],bool t[33][33]) { bool tmp[33][33]; int top=n*m; memset(tmp,0,sizeof(tmp)); for(int k=0;k<top;k++) for(int i=0;i<top;i++) for(int j=0;j<top;j++) { tmp[i][j]|=(s[i][k]&t[k][j]); } for(int i=0;i<top;i++) for(int j=0;j<top;j++) s[i][j]=tmp[i][j]; } int main() { int T; scanf("%d",&T); while(T--) { memset(g,0,sizeof(g)); scanf("%d%d",&n,&m); for(int i=0;i<n;i++) for(int j=0;j<m;j++) { int id=i*m+j; scanf(" ((%d,%d),(%d,%d),(%d,%d),(%d,%d))",&x[1],&y[1],&x[2],&y[2],&x[3],&y[3],&x[4],&y[4]); if(i!=n-1||j!=m-1) { for(int k=1;k<=4;k++) { int tid=(x[k]-1)*m+y[k]-1; g[id][tid]=1; } } } int q; scanf("%d",&q); while(q--) { int tmp; scanf("%d",&tmp); bool sum[33][33]; for(int i=0;i<n*m;i++) for(int j=0;j<n*m;j++) { if(i==j) sum[i][j]=1; else sum[i][j]=0; tg[i][j]=g[i][j]; } while(tmp) { if((tmp&1)) mul(sum,tg); mul(tg,tg); tmp>>=1; } if(sum[0][n*m-1]==0) printf("False "); else { int flag=0; for(int i=1;i<n*m-1;i++) { if(g[0][i]!=0) { flag=1; break; } } if(flag) printf("Maybe "); else printf("True "); } } printf(" "); } return 0; }