bzoj1297: [SCOI2009]迷路
矩阵。
一个图的邻接矩阵的m次幂相当于 长度恰好为m的路径数。这要求边权为1。
因为边权小于等于9,所以可以把一个点拆成9的点。 拆成的第(i+1)个点向第i个点连边。
如果存在边(u,v,w) 就由u点向v拆成的第w个点连边,这样表明w次以后就可以到达v点。
这个拆点很牛啊,不过第一眼连邻接矩阵都没看出来。。
#include<cstdio> #include<algorithm> #include<cstring> using namespace std; const int maxn = 100 + 10; const int mod = 2009; struct Matrix { int a[maxn][maxn]; int n; int* operator [] (int x) { return a[x]; } Matrix operator* (Matrix b) { Matrix c; c.n=n; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) for(int k=1;k<=n;k++) c[i][k]=(c[i][k]+a[i][j]*b[j][k])%mod; return c; } Matrix operator^ (int e) { Matrix res,tmp=*this; res.init(n); while(e) { if(e&1) res=res*tmp; tmp=tmp*tmp; e>>=1; } return res; } void output() { for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) printf("%d ",a[i][j]); printf("\n"); } } void input() { scanf("%d",&n); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) scanf("%d",&a[i][j]); } void init(int k) { n=k; for(int i=1;i<=n;i++) a[i][i]=1; } Matrix() { memset(a,0,sizeof(a)); } }g,res; int n,m,k,vid; int id[maxn][maxn]; int main() { scanf("%d%d",&n,&m); k=n*9; res.n=g.n=k; for(int i=1;i<=n;i++) for(int j=1;j<=9;j++) id[i][j]=++vid; for(int i=1;i<=n;i++) for(int j=1;j<9;j++) g[id[i][j+1]][id[i][j]]=1; for(int i=1,t;i<=n;i++) for(int j=1;j<=n;j++) { scanf("%1d",&t); if(!t) continue; g[id[i][1]][id[j][t]]=1; } for(int i=1;i<=k;i++) res[i][i]=1; res=res*(g^m); printf("%d\n",res[id[1][1]][id[n][1]]); return 0; }