这里是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即可;
这个里面不能用向下递归的方法来求power而是要用while循环
写法是:
while( n ){
if( n % 2 == 1 ){
ans = multiply( ans, b );
}
b = multiply( b, b );
n /= 2;
}
为什么是这样呢?
当我们要求a^10的时候
模拟上面的过程
a^10 这一步n/2的时候不会丢失任何数 如果在这一步丢失 则丢失b = a
a^5 a^5 这一步n/2的时候数会丢失 如果在这一步丢失 则丢失b = a^2
a^2 a ^2 a^2 a^2 这一步n/2的时候不会丢失任何数 如果在这一步丢失 则丢失 b = a^4
a a a a a a a a 这一步n/2的时候数会丢失 如果在这一步丢失 则丢失 b = a^8
然后我们只需要把所有丢失的数乘起来即是最后的答案
AC代码如下:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAX_N = 30;
const int MAX_M = 30;
int M, N, T;
struct Matrix{
int M, N;
int num[MAX_M][MAX_N];
void init(){
memset( num, 0, sizeof( num ) );
}
};
Matrix multiply( Matrix a, Matrix b ){
Matrix c;
c.M = a.M;
c.N = b.N;
c.init();
for( int i = 1; i <= c.M; i++ ){
for( int j = 1; j <= c.N; j++ ){
for( int k = 1; k <= a.N; k++ ){
c.num[i][j] |= a.num[i][k] & b.num[k][j];
}
}
}
return c;
}
Matrix get_mul_pow( Matrix a, int n ){
Matrix ans, b;
b = a;
ans = a;
ans.init();
for( int i = 1; i <= M * N; i++ ){
ans.num[i][i] = 1;
}
while( n ){
if( n % 2 == 1 ){
ans = multiply( ans, b );
}
b = multiply( b, b );
n /= 2;
}
return ans;
}
int main(){
scanf( "%d", &T );
while( T-- ){
scanf( "%d%d", &M, &N );
Matrix ans;
ans.init();
ans.M = ans.N = M * N;
for( int i = 1; i <= M; i++ ){
for( int j = 1; j <= N; j++ ){
int x[5], y[5];
getchar();
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 );
for( int k = 1; k <= 4; k++ ){
ans.num[(i-1)*N+j][(x[k]-1)*N+y[k]] = 1;
}
}
}
for( int i = 1; i <= M * N; i++ ){
ans.num[N*M][i] = 0;
}
int Q, n;
scanf( "%d", &Q );
while( Q-- ){
scanf( "%d", &n );
Matrix tt;
tt = get_mul_pow( ans, n );
if( tt.num[1][M*N] == 0 ){
printf( "False\n" );
}else{
int i;
for( i = 1; i <= M * N; i++ ){
if( tt.num[1][i] == 1 ){
break;
}
}
if( i == M * N ){
printf( "True\n" );
}else{
printf( "Maybe\n" );
}
}
}
puts("");
}
return 0;
}