题目链接
http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=4320
思路
题意是给你一张图,起点是1,终点是m*n,一旦走到终点就立马停止不能再走了,问你可不能正好P步到达终点。可能输出maybe,一定输出true,不可能输出false。
这里要用到离散数学的一个定理,就是一张图的邻接矩阵A,P次方后得到的邻接矩阵 AP 中的元素 aij 表示从i到j有几条长度为P的通路。因为如果 aik=1 , bkj=1 ,那么 cij=aik×bkj=1 ,和floyd有点像。
所以对邻接矩阵求P次幂,看(1,m*n)有没有值,如果没有肯定是false,如果有再看(1,1~m*n-1),全为0就是true,否则就是maybe。
然而这题有点特殊,就是走到终点后不能走了,也就是从终点出发的路数永远为0,那么直接把矩阵的最后一行清零即可。
然后直接求P次方肯定超时,P有100,000,000呢,所以用到了快速幂。所谓快速幂就是把P化成二进制,然后按每一位的权值来求次方,可以优化到 log2P ,再加上矩阵乘法本身的 N3 ,总时间复杂度为 (m∗n)3×log2P ,其中P最大 109 ,m*n最大25,完全可以承受。
AC代码
#include <bits/stdc++.h>
using namespace std;
const int N=50;
struct matrix
{
int mat[N][N];
matrix(void)
{
memset(mat,0,sizeof mat);
}
matrix friend operator * (matrix a, matrix b)
{
int n=N;
matrix ans;
for(int i=0 ; i<n ; ++i)
{
for(int j=0 ; j<n ; ++j)
{
int sum=0;
for(int k=0 ; k<n ; ++k)
{
sum+=a.mat[i][k]*b.mat[k][j];
}
ans.mat[i][j]=sum;
}
}
return ans;
}
};
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int m,n;
scanf("%d%d",&n,&m);
getchar();
matrix z;
for(int i=0 ; i<n ; ++i)
{
for(int j=0 ; j<m ; ++j)
{
int a,b,c,d,e,f,g,h;
scanf("((%d,%d),(%d,%d),(%d,%d),(%d,%d))",&a,&b,&c,&d,&e,&f,&g,&h);
a--;b--;c--;d--;e--;f--;g--;h--;
getchar();
z.mat[i*m+j][a*m+b]=1;
z.mat[i*m+j][c*m+d]=1;
z.mat[i*m+j][e*m+f]=1;
z.mat[i*m+j][g*m+h]=1;
}
}
for(int j=0 ; j<n*m ; ++j)//最后一行清零
z.mat[n*m-1][j]=0;
int q;
scanf("%d",&q);
while(q--)
{
int t;
scanf("%d",&t);
matrix zz,ans;
zz=z;
for(int i=0 ; i<n*m ; ++i)//初始化为单位矩阵
ans.mat[i][i]=1;
while(t)
{
if(t&1)
{
ans=ans*zz;
}
zz=zz*zz;
t>>=1;
}
if(ans.mat[0][m*n-1]==0)
{
printf("False\n");
}
else
{
bool flag=0;
for(int j=0 ; j<m*n-1 ; ++j)
{
if(ans.mat[0][j])
{
flag=1;
break;
}
}
if(flag)printf("Maybe\n");
else printf("True\n");
}
}
printf("\n");
}
return 0;
}