【题目描述】
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]
a[u][v]=∑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];
}