【题解】p4159:SCOI 2009 迷路:(矩乘优化递推)
\(Description:\)
该有向图有 N 个节点,windy从节点 0 出发,他必须恰好在 T 时刻到达节点 N-1。 现在给出该有向图,你能告诉windy总共有多少种不同的路径吗?
\(Sample Input 1\):
2 2
11
00
\(Sample Output:\)
1
很明显(不明显
关于邻接矩阵有一个神奇的性质,如果邻接矩阵中只有0/1代表两点是否连通,那么从s走到t且恰好经过k条边的方案总数,就是该邻接矩阵的k次幂中[s,t]的值。
对于只有0,1的矩阵我们考虑一开始的矩阵\(f_1 [i][j]\)就表示\(i\)到\(j\)一步可以走到的方案数。
\(f_t [i][j]\)表示走了t步的路径条数
那么只要对每一次的矩阵\(f_t[i][j]\)可以从\(f_{t-1}[i][j]\)和\(f_1[i][j]\)乘一乘得到。
转移方程:
\(f_t[i][j]=\sum_{k=1}^{n}f_t[i][j]*f_1[i][j]\)
又发现(没发现这个可以用矩乘加速。
那么我们把这个代码码出来,然后发现好像过不了边权不为1,0的情况,好惊恐~~
然后我们考虑把这些边权附加到点上。
把每个点拆成9个
那么没输入一个边权只要强制这个点走到这个点的第边权个就可以转换成01矩阵了。
性质为什么我好不太理解。。。
#include<bits/stdc++.h>
using namespace std;
int n,t,m;
const int MAXN=100;
const int p=2009;
char s[MAXN+5][MAXN+5];
struct matrix{
int a[MAXN+5][MAXN+5];
inline void clear(){
memset(a,0,sizeof(a));
}
inline matrix operator *= (matrix b){
matrix ret;ret.clear();
for(int i=1;i<=n;++i)for(int j=1;j<=n;++j)for(int k=1;k<=n;++k)
ret.a[i][j]=(ret.a[i][j]+this->a[i][k]*b.a[k][j]%p)%p;
return *this=ret;
}
};
inline matrix power(matrix a,int b){
matrix ret;ret.clear();
for(int i=1;i<=n;++i)ret.a[i][i]=1;
for(;b;a*=a,b>>=1)if(b&1)ret*=a;
return ret;
}
matrix f;
int main(){
f.clear();
scanf("%d%d",&n,&t);
for(int i=1;i<=n;++i)scanf("%s",s[i]+1);
m=n;n=9*n;
for(int i=1;i<=m;++i)for(int j=1;j<=8;++j)
f.a[(i-1)*9+j][(i-1)*9+j+1]=1;
for(int i=1;i<=m;++i)for(int j=1;j<=m;++j){
int x=s[i][j]^48;
if(!x)continue;
f.a[(i-1)*9+x][(j-1)*9+1]=1;
}
f=power(f,t);
printf("%d\n",f.a[1][m*9-8]);
return 0;
}