BZOJ1297 [SCOI2009]迷路 矩阵乘法
欢迎访问~原文出处——博客园-zhouzhendong
去博客园看该题解
题目传送门 - BZOJ1297
题意概括
有向图有 N 个节点,从节点 0 出发,他必须恰好在 T 时刻到达节点 N-1。 现在给出该有向图,问总共有多少种不同的路径吗? 注意:不能在某个节点逗留,且通过某有向边的时间严格为给定的时间。
题解
矩阵乘法。
把一个点拆成9个,分别是time+0,time+1,time+2,...,time+8。
然后根据输入转移,构建矩阵即可。
然后基础矩阵跑一跑就可以了。
插曲
悲催,一个小错找了1个小时:
把设置单位矩阵打成这样了……
代码
#include <cstring> #include <cstdio> #include <algorithm> #include <cstdlib> #include <cmath> using namespace std; const int N=10+5,maxm=N*10,mod=2009; int n,m,t; char str[N][N]; struct Mat{ int v[maxm][maxm]; void set(){ memset(v,0,sizeof v); } void set1(){ set(); for (int i=0;i<m;i++) v[i][i]=1; } Mat operator * (Mat a){ Mat ans; ans.set(); for (int i=0;i<m;i++) for (int j=0;j<m;j++) for (int k=0;k<m;k++) ans.v[i][j]=(ans.v[i][j]+v[i][k]*a.v[k][j])%mod; return ans; } }M,Mans; Mat MatPow(Mat x,int y){ Mat M,xx=x; M.set1(); while (y){ if (y&1) M=M*xx; xx=xx*xx; y>>=1; } return M; } int Hash(int x,int y){ return x*9+y; } int main(){ scanf("%d%d",&n,&t); m=n*9; for (int i=0;i<n;i++) scanf("%s",str[i]); M.set(); for (int i=0;i<n;i++) for (int j=0;j<8;j++) M.v[Hash(i,j+1)][Hash(i,j)]++; for (int i=0;i<n;i++) for (int j=0;j<n;j++) if (str[i][j]!='0') M.v[Hash(i,0)][Hash(j,str[i][j]-'1')]++; Mans=MatPow(M,t); printf("%d",Mans.v[0][Hash(n-1,0)]); return 0; }