【矩阵快速幂】迷路

【题目描述】
Windy 在有向图中迷路了。 该有向图有 N 个节点,Windy 从节点 0 出发,他必须恰好在 T 时刻到达节点 N−1
现在给出该有向图,你能告诉 Windy 总共有多少种不同的路径吗?
注意:Windy 不能在某个节点逗留,且通过某有向边的时间严格为给定的时间。

【输入描述】
第一行包含两个整数,N,T。
接下来有 N 行,每行一个长度为 N 的字符串。第 i 行第 j 列为 0 表示从节点 i 到节点 j 没有边,为 1 到 9 表示从节点 i 到节点 j 需要耗费的时间。

【输出描述】
包含一个整数,可能的路径数,这个数可能很大,只需输出这个数除以 2009 的余数。
【样例1】
样例输入 1
2 2
11
00
样例输出 1
1
样例说明 1
0→0→1
【样例2】
样例输入 2
5 30
12045
07105
47805
12024
12345
样例输出 2
852

【思路】

这道题需要用到一个定理:对于一个图,若其邻接矩阵中的值只有0和1,则该邻接矩阵的t次幂可以从表示走t步到达v的方案数。至于原因可以结合矩阵乘法运算的规则进行理解。
a [ u ] [ v ] = b [ u ] [ i ] c [ i ] [ v ] a[u][v]=\sum b[u][i]*c[i][v]
若b数组表示走i步的方案,c数组表示走j步的方案,则矩阵乘法后的a数组就是走(i+j)步的方案。
其实就是一个乘法原理。
于是对于上面这个题,我们可以通过拆点把所有边边权变成1,然后再用矩阵快速幂就ok了。
代码:

#include<cstdio>
#include<iostream>
#include<queue>
#include<algorithm>
#include<cstring>
#include<string>
#include<vector>
#define re register
using namespace std;
int mod=2009,t;int n;
struct node{
	int a[120][120];
	int n;
	node (int _n=0)
	{
		memset(a,0,sizeof(a));
		n=_n;
	}
	friend node operator *(node A,node B);
	friend node operator ^(node A,int p);
}A(100),B(100);
node operator *(node A,node B)
{
	node C(A.n);
	for(int re i=1;i<=A.n;i++)
		for(int re k=1;k<=A.n;k++)
			for(int re j=1;j<=A.n;j++)
				C.a[i][j]+=A.a[i][k]*B.a[k][j]%mod,
				C.a[i][j]%=mod;
	return C; 
}
node operator ^(node A,int p)
{
	node C(A.n);
	for(int re i=1;i<=A.n;i++)C.a[i][i]=1;
	while(p)
	{
		if(p&1)C=C*A;
		A=A*A;
		p>>=1;
	}
	return C;
}
char s[101];
int main()
{
	scanf("%d %d\n",&n,&t);
	A.n=n*9;
	for(int re i=1;i<=n;i++)
	{
		for(int re j=1;j<=8;j++)
			A.a[(i-1)*9+j][(i-1)*9+j+1]=1;
	}
	for(int re i=1;i<=n;i++)
	{
		scanf("%s",s+1);
		for(int re j=1;j<=n;j++)
		{
			char c=s[j];
			if(c<='9'&&c>'0')
				A.a[9*(i-1)+(c-48)][(j-1)*9+1]=1;
		}
	}
	A=A^t;
	cout<<A.a[1][n*9-8];
}

猜你喜欢

转载自blog.csdn.net/weixin_44111457/article/details/86696059