设有向图D=<V,E>,V={v1,v2,…,vn}D=<V,E>, V = \lbrace v_1,v_2, \ldots, v_n \rbraceD=<V,E>,V={v1,v2,…,vn},令aij(1)a_{ij}^{(1)}aij(1)顶点viv_ivi邻接到顶点vjv_jvj的边的条数,称(aij(1))n×n(a_{ij}^{(1)})_{n \times n}(aij(1))n×n为DDD的邻接矩阵,简记为AAA。
定理:AAA的lll次幂Al(l≥1)A^l(l \geq 1)Al(l≥1)中元素aij(l)a_{ij}^{(l)}aij(l)为DDD中viv_ivi到vjv_jvj长度为lll的通路数。
对于此题,采用类邻接矩阵,只需记录viv_ivi是否可以到达vjv_jvj,即边数为111。
对于每次询问,跑矩阵快速幂判断即可。
AC代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
struct mat
{
ll a[50][50];
};
int szie;
mat A, B, V;
mat mat_mul(mat x, mat y)
{
mat res;
memset(res.a, 0, sizeof(res.a));
for(int i = 1; i <= szie; i++){
for(int j = 1; j <= szie; j++){
for(int k = 1; k <= szie; k++){
res.a[i][j] = (res.a[i][j] + x.a[i][k] * y.a[k][j]);
}
}
}
return res;
}
mat pow_matrix_mod(int n)
{
mat c = A, ans = V;
while(n){
if(n & 1) ans = mat_mul(ans, c);
c = mat_mul(c, c);
n >>= 1;
}
return ans;
}
int main()
{
int T, n, m;
cin >> T;
while (T--) {
memset(V.a, 0, sizeof(V.a));
memset(A.a, 0, sizeof(A.a));
memset(B.a, 0, sizeof(B.a));
scanf("%d %d", &n, &m);
getchar();
szie = n*m;
for (int i = 1; i <= szie; ++i) V.a[i][i] = 1;
int x1, y1, x2, y2, x3, y3, x4, y4;
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= m; ++j) {
scanf("((%d,%d),(%d,%d),(%d,%d),(%d,%d))",&x1, &y1, &x2, &y2, &x3, &y3, &x4, &y4);
if (i == n && j == m) continue;
int p = (i-1)*m+j;
A.a[p][(x1-1)*m+y1] = 1;
A.a[p][(x2-1)*m+y2] = 1;
A.a[p][(x3-1)*m+y3] = 1;
A.a[p][(x4-1)*m+y4] = 1;
getchar();
}
}
int Q, l;
scanf("%d", &Q);
while (Q--) {
scanf("%d", &l);
B = pow_matrix_mod(l);
if (B.a[1][szie] == 0) cout << "False" << '\n';
else {
int flag = 0;
for (int i = 1; i < szie; ++i) {
if (B.a[1][i]) {
flag = 1;
break;
}
}
if (!flag) cout << "True" << '\n';
else cout << "Maybe" << '\n';
}
}
cout << '\n' ;
}
return 0;
}