题目描述
道路千万条,安全第一条!HF校区到YB校区有很多种走法,我们可以把走法看成N个节点的有向图,假设HF代表0号节点,YB代表N-1号节点,GM想从0号节点出发,到N-1号节点,但必须恰好在T时刻到达!你能告诉GM一共有多少种走法吗?注意:GM不能在某个节点逗留,且通过某有向边时严格为给定时间(边权)。
输入
满足 2 <= N <= 10 ; 1 <= T <= 1000000000。
输出
包含一个整数,可能的路径数,这个数可能很大,只需输出这个数除以2009的余数。
样例输入
2 2
11
00
样例输出
1
解题思路
首先想一个简单的情况,如果只是有0,1所组成的矩阵我们该如何求呢
例如
这里有一个性质,也就是这一个矩阵的t次幂所在的s[i][j]正是从i到j的时间为t的路径数。
震惊吧,我也很震惊...
仔细想一想其实也确实是这样。
我们先看2次方
(1,1)就是意义为1到1中途经过1的情况,就相当于走了2(时间)。而(1,2)则是1到2中途经过2的情况,这样推下去确实也没有问题,因为(i,j)为1则就说明了i,j有路。
其实我们回到矩阵乘法的基本定义
其实也就这么做出来。
但这道题又不是由0,1构成,我们就需要拆点。
例如
我们就拆成了
我们就是将每一个点拆成它的最大边权个(这样才能构造出全部为1,0)
拆点过程呢...看代码吧,我觉得自己想一下还是可以理解的。(模板大法好)
#include<cstdio>
#include<cstring>
#include<queue>
#include<iostream>
#include<algorithm>
#include<vector>
#include<cmath>
using namespace std;
struct matrix {
int n,m;
long long c[150][150];
matrix (){
memset(c,0,sizeof(c));
}
matrix operator * (const matrix &x)const{
matrix tmp ;
tmp.n = n;
tmp.m = x.m;
for (int i = 1;i <= tmp.n;i ++)
for (int j = 1;j <= tmp.m;j ++)
for (int k = 1;k <= x.n;k ++)
tmp.c[i][j] = (tmp.c[i][j] + c[i][k] * x.c[k][j]) % 2009;
return tmp;
}
}A,B;
int n,t;
long long maxn;
int xb(int x,int y){
return (x - 1) * maxn + y;
}
matrix qkpow(matrix x,int y){
matrix ans;
ans.n = ans.m = x.n;
for (int i = 1;i <= ans.n;i ++)
ans.c[i][i] = 1;
while (y){
if (y & 1)
ans = ans * x;
x = x * x;
y /= 2;
}
return ans;
}
int main(){
scanf ("%d%d",&n,&t);
for (int i = 1;i <= n;i ++)
for (int j = 1;j <= n;j ++){
scanf ("%1lld",&A.c[i][j]);
maxn = max(A.c[i][j],maxn);
}
for (int i = 1;i <= n;i ++){
for (int j = 1;j < maxn;j ++)
B.c[xb(i,j)][xb(i,j+1)] = 1;
for (int j = 1;j <= n;j ++){
if (A.c[i][j] != 0)
B.c[xb(i,A.c[i][j])][xb(j,1)] = 1;
}
}
B.n = B.m = maxn * n;
B = qkpow(B,t);
printf("%lld
",B.c[1][(n - 1) * maxn + 1]);
}
花絮
广搜爆炸
深搜爆炸
(搜索真好用)