BZOJ1875 SDOI2009 HH去散步 矩阵乘法
题意:给定一张无向图,求A到B的路径中,经过的边数为T且不存在连续的两步经过同一条边的路径条数。
题解:没有第二个条件的话矩阵快速幂可做。有第二个条件我们可以边化点,然后虚拟两个节点S和T作为起点和终点,其中S与含A的边相连,T和含B的边相连,由于走到B需要额外的一步,因此求邻接矩阵的T+1次幂
#include <cstdio> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> using namespace std; #define P 45989 const int MAXN=20+2; const int MAXM=60+2; int N,M,T,A,B,cnt; struct Edge{ int u,v; Edge(){} Edge(int _u,int _v):u(_u),v(_v){} }e[2*MAXM]; struct Matrix { int a[2*MAXM][2*MAXM]; Matrix(){ memset(a,0,sizeof(a));} void Init(){ memset(a,0,sizeof(a)); for(int i=0;i<=N;i++) a[i][i]=1; } int* operator [](int x){ return a[x]; } Matrix operator *(Matrix b){ Matrix res; for(int i=0;i<=N;i++) for(int j=0;j<=N;j++) for(int k=0;k<=N;k++) res[i][k]=(res[i][k]+a[i][j]*b[j][k])%P; return res; } Matrix operator ^(int t){ Matrix res,tmp=*this;res.Init(); while(t){ if(t&1) res=res*tmp; tmp=tmp*tmp; t>>=1; } return res; } }s; int main(){ cin >> N >> M >> T >> A >> B; for(int i=1,u,v;i<=M;i++){ scanf("%d %d",&u,&v); e[cnt++]=Edge(u,v),e[cnt++]=Edge(v,u); } for(int i=0;i<cnt;i++) for(int j=0;j<cnt;j++) if(e[i].v==e[j].u && i!=(j^1)) s.a[i][j]=1; for(int i=0;i<cnt;i++){ if(e[i].u==A) s.a[cnt][i]=1; if(e[i].v==B) s.a[i][cnt+1]=1; } N=cnt+1,s=s^(T+1); cout << s.a[cnt][cnt+1] << endl; return 0; }