题目大意
w
i
n
d
y
windy
windy在有向图中迷路了。
该有向图有
N
N
N 个节点,
w
i
n
d
y
windy
windy从节点
0
0
0 出发,他必须恰好在
T
T
T 时刻到达节点
N
−
1
N-1
N−1。
现在给出该有向图,你能告诉
w
i
n
d
y
windy
windy总共有多少种不同的路径吗?
注意:
w
i
n
d
y
windy
windy不能在某个节点逗留,且通过某有向边的时间严格为给定的时间。
题目解析
由于这道题的
T
T
T 很大,线性算法是过不了的,所以我们考虑矩阵乘法。
这道题图中的边权为
1
9
1~9
1 9,比较小,所以考虑拆点,为了方便表示,把编号为
i
i
i的点拆为
i
∗
10
+
1
i
∗
10
+
9
i*10+1~i*10+9
i∗10+1 i∗10+9 一共
9
9
9 个节点。如果
i
i
i 到
j
j
j 有一条权值为
k
k
k 的路径,那么就把矩阵中
[
i
∗
10
+
k
,
j
∗
10
+
1
]
[i*10+k,j*10+1]
[i∗10+k,j∗10+1]的值设为 1,相当于先从
i
∗
10
+
1
→
i
∗
10
+
k
i*10+1→i*10+k
i∗10+1→i∗10+k 走过
k
−
1
k-1
k−1条长度为
1
1
1 的路径,再在
i
∗
10
+
k
→
j
∗
10
+
1
i*10+k→j*10+1
i∗10+k→j∗10+1 走过
1
1
1 条长度为
1
1
1 的路径,总长度为
k
k
k,跑一遍快速幂,
[
1
∗
10
+
1
]
[
n
∗
10
+
1
]
[1*10+1][n*10+1]
[1∗10+1][n∗10+1]的值即是方案总数。
代码
#include<bits/stdc++.h>
#define N 105
#define M 2009
using namespace std;
int n,t,an;
int m[N][N],tmp[N][N],ans[N][N];
char c;
void mul(int a[N][N],int b[N][N])
{
memset(tmp,0,sizeof(tmp));
for(int i=0;i<an;i++)
for(int j=0;j<an;j++)
for(int k=0;k<an;k++)
tmp[i][j]=(tmp[i][j]+a[i][k]*b[k][j])%M;
memcpy(a,tmp,sizeof(tmp));
}
void qpow()
{
for(int i=0;i<an;i++) ans[i][i]=1;
while(t)
{
if(t&1) mul(ans,m);
mul(m,m);
t>>=1;
}
}
int main()
{
cin>>n>>t;
an=n*9;
for(int i=0;i<n;i++)
{
for(int j=0;j<8;j++)
m[i*9+j][i*9+j+1]=1;
for(int j=0,num;j<n;j++)
{
cin>>c;
num=c-'0';
if(num) m[i*9+num-1][j*9]=1;
}
}
qpow();
cout<<ans[0][(n-1)*9];
}