题目大意:有向图有 n(n<=10) 个节点,有若干条有向边,经过一条边需要花费一些时间。从节点 0 出发,必须恰好在 T(T<=1000000000) 时刻到达节点 N-1。 总共有多少种不同的路径? 注意:不能在某个节点逗留,且通过某有向边的时间严格为给定的时间。
若知道第i秒的方案,可以推出后面10秒内的部分方案。设第i秒的经过节点j的方案数为f(i,j),则f(i,j)=sigma{f(i-k,t)} ,其中t到j有一条需要消耗k个单位时间的单向边。很明显的递推,可是T很大,想到用矩阵快速幂加速递推。
定义方案矩阵mat为第i秒的经过各点的方案数,可是递推时会可能会更新后10秒的状态,而一个矩阵只能代表1秒。这里采用将一个点分裂成10个点的方法,第一个点代表第i秒经过节点j的方案数,另外9个点为临时存储方案的点,表示从j出发已经走了k秒。
例如从j到t需要x秒,已知i-1秒的状态想求第i秒的状态,那么第i秒经过节点t的方案中就有一部分是在i-1秒时从节点j已经走了x-1秒的方案。以此类推,详见代码。
#include <cstdio>]
#include <cstring>
#define N 100
#define MOD 2009
using namespace std;
struct Matrix {
int a[N+5][N+5];
Matrix() { memset(a,0,sizeof a); }
Matrix operator * (const Matrix& rhs) const {
Matrix tmp;
for(int i=0;i<100;i++)
for(int j=0;j<100;j++)
for(int k=0;k<100;k++)
(tmp.a[i][j]+=a[i][k]*rhs.a[k][j])%=MOD;
return tmp;
}
}mat,ini,trans;
Matrix f_pow(Matrix x,int y) {
Matrix tmp=ini;
while(y) {
if(y&1) tmp=tmp*x;
x=x*x;
y>>=1;
}
return tmp;
}
char a[15][15];
int main() {
int n,m;
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++) scanf("%s",a[i]);
for(int i=0;i<n;i++)
for(int j=1;j<10;j++)
trans.a[i*10+j-1][i*10+j]=1;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++) {
int x=a[i][j]-'0';
if(!x) continue;
trans.a[i*10+x-1][j*10]=1;
}
for(int i=0;i<100;i++) ini.a[i][i]=1;
mat.a[0][0]=1;
mat=mat*f_pow(trans,m);
printf("%d\n",mat.a[0][(n-1)*10]);
return 0;
}