您的位置:首页 > 其它

ZOJ 3497 Mistwald (矩阵快速幂解决类似图论问题)

2016-02-01 23:10 387 查看
点击打开链接

这道题的题意大概是有一个n*m的图,会告诉你每一个点的出边,与哪四个点相连(可能是重复的),注意这是单向的连接。问从起点(1,1)开始,走P步之后,是一定到终点(n,m),还是可能到,还是不可能到终点?其中在行走的过程中,除了第P步到达的点,其他都不能是终点,但是可以重复经过其他点。

这道题由于方便起见,把起点设置为(0,0),终点就是(n-1,m-1),按行优先遍历,给每个点按顺序编号,然后再做一个邻接矩阵A。A^K的第i行第j列的数代表从编号为i的点走k步是否能到达j。

最关键的一步,就是把终点的出边给删掉。这样就永远不可以从终点出发到另外一个点了。

理解的过程,可以把A^K的计算过程在脑海里模拟一遍,先假设不考虑终点是不是经过,那么新的矩阵的a[i][j]是如何产生的,特别要关注 a[i][k]&&a[k][j] ,k相当于从i到j的一个中间点。

再讨论一下p=0的特殊情况。

#include<cstdio>
#include<cstring>
struct matrix{
int a[30][30];
}base, ans, re;
int n, m;
matrix multiply(matrix u, matrix v)
{
matrix tmp;
for (int i = 0; i < n*m; i++)
for (int j = 0; j < n*m; j++)
{
tmp.a[i][j] = 0;
for (int k = 0; k < n*m; k++)
if (u.a[i][k] && v.a[k][j])
{
tmp.a[i][j] = 1;
break;
}
}
return tmp;
}
void fast_mod(int l)
{
while (l)
{
if (l & 1) ans = multiply(ans, base);
base = multiply(base, base);
l >>= 1;
}
}
int main()
{
int t, q, p, s;
int x[5], y[5], num[5];
scanf("%d", &t);
getchar();
while (t--)
{
memset(re.a, 0, sizeof(re.a));
scanf("%d%d", &m, &n);
getchar();
for (int i = 0; i < m; i++)
for (int j = 0; j < n; j++)
{
scanf("((%d,%d),(%d,%d),(%d,%d),(%d,%d))", &x[0], &y[0], &x[1], &y[1], &x[2], &y[2], &x[3], &y[3]);
getchar(); // 输入格式要注意 注意要吃回车
if (i == (m-1) && j == (n-1)) continue; //最关键的一步
num[4] = i*n+j;
for (int k = 0; k < 4; k++) num[k] = (x[k]-1)*n + y[k]-1;
for (int k = 0; k < 4; k++)
re.a[num[4]][num[k]] = 1;
}
scanf("%d", &q);
getchar();
while (q--)
{
scanf("%d", &p);
getchar();
if (p == 0)
{
if (n == 1 && m == 1) printf("True\n");
else printf("False\n");
continue;
}
memcpy(base.a, re.a, sizeof(base.a)); // 把一个数组赋值给另外一个数组
memset(ans.a, 0, sizeof(ans.a));
for (int i = 0; i < n*m; i++) ans.a[i][i] = 1;
fast_mod(p);
s = 0;
for (int i = 0; i < n*m-1; i++)
if (ans.a[0][i]) s++;
if (ans.a[0][n*m-1] == 1)
{
if (s == 0) printf("True\n");
else printf("Maybe\n");
}
else printf("False\n");
}
printf("\n");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: