windy在有向图中迷路了。 该有向图有 N 个节点,windy从节点 0 出发,他必须恰好在 T 时刻到达节点 N-1。 现在给出该有向图,你能告诉windy总共有多少种不同的路径吗? 注意:windy不能在某个节点逗留,且通过某有向边的时间严格为给定的时间。
根据题意,可以写出转移方程
\[f_{i,j}=\sum f_{r,j-w[r]}
\]
\(f_{i,j}\)表示第\(j\)时刻在第\(i\)个点时的方案数,\(r\)为\(i\)的前驱,\(w[r]\)为距离
而\(T\le 10^9\),所以肯定是不可行的,就要用到矩阵加速
如果对于上面那个转移方程是无法矩阵加速的
但是边权只有\(1…9\),我们可以把\(j\)分开表示,也就是把所有距离的情况都表示出来
那么对于上面的那个转移方程就有两种转移形式
-
这个距离\(j\)不是真正的距离,那么\(f_{r,j}\)可以从\(f_{r,j-1}\)继承
-
这个\(j\)是真正的距离,那么\(f_{r,j}\)对\(f_{i,j}\)是有贡献的
代码和拆点一样= =
Code
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int n,t,d[500][500],s[500][500],b[500][500],p=2009;
char ch;
void jzc(int x[500][500],int y[500][500])
{
for (int i=1;i<=n*9;i++)
for (int j=1;j<=n*9;j++)
for (int k=1;k<=n*9;k++)
b[i][j]=(b[i][j]+x[i][k]*y[k][j]%p)%p;
for (int i=1;i<=n*9;i++)
for (int j=1;j<=n*9;j++)
x[i][j]=b[i][j],b[i][j]=0;
}
int main()
{
cin>>n>>t;
for (int i=1;i<=n;i++)
{
for (int j=1;j<=8;j++) //第一个的继承关系
d[i+j*n][i+(j-1)*n]=1;
for (int j=1;j<=n;j++)
{
cin>>ch;
d[i][j+n*((ch-'0')-1)]=1; //真正的边
}
}
for (int i=1;i<=n*9;i++)
s[i][i]=1;
while (t)
{
if (t&1)jzc(s,d);
jzc(d,d);
t>>=1;
}
cout<<s[1][n]<<endl;
return 0;
}