【bzoj1875】【JZYZOJ1354】[SDOI2009]HH去散步 矩阵快速幂 点边转换
http://172.20.6.3/Problem_Show.asp?id=1354
题意:求从起始点到终点走过的路程为x有多少种走法,不保证两点间只有一条路,刚走完一条路时不能原路返回,每条路长度为1。
把每条路更换为正反两条边,再造一条出到起点的边s造一条入为终点的边t,将每一条边作为邻接矩阵中的点,矩乘即可
注意题意告诉我们一条路中的正反两条边不能相连。
代码
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 const int maxn=10010; 5 const double eps=1e-8; 6 const int modn=45989; 7 int n,m,d,s,t; 8 struct mat{ 9 long long e[130][130]; 10 mat(){ memset(e,0,sizeof(e)); } 11 };mat a; 12 struct nod{ 13 int y; 14 int f; 15 int rev; 16 int next; 17 }e[200]; 18 int tot=0; 19 int head[50]={}; 20 mat Mul(mat x,mat y){ 21 mat z; 22 for(int i=0;i<=m*2+1;i++){ 23 for(int j=0;j<=m*2+1;j++){ 24 for(int k=0;k<=m*2+1;k++){ 25 z.e[i][j]+=x.e[i][k]*y.e[k][j]; 26 z.e[i][j]%=modn; 27 } 28 } 29 } 30 return z; 31 } 32 mat Pow(mat x,int k){ 33 mat z; 34 for(int i=0;i<=m*2+1;i++){ 35 z.e[i][i]=1; 36 } 37 while(k>0){ 38 if(k&1){ 39 z=Mul(z,x); 40 } 41 x=Mul(x,x); 42 k/=2; 43 } 44 return z; 45 } 46 void init(int x,int y,int rev){ 47 e[++tot].y=y; 48 e[tot].next=head[x]; 49 e[tot].rev=rev; 50 head[x]=tot; 51 } 52 void dfs(int x,int v){ 53 int y; 54 if(x==t){ 55 a.e[v][2*m+1]=1; 56 } 57 for(int i=head[x];i;i=e[i].next){ 58 y=e[i].y; 59 if(v!=e[i].rev){ 60 a.e[v][i]=1; 61 } 62 if(!e[i].f){ 63 e[i].f=1; 64 dfs(y,i); 65 } 66 } 67 } 68 int main(){ 69 scanf("%d%d%d%d%d",&n,&m,&d,&s,&t); 70 s+=1,t+=1; 71 int x,y; 72 for(int i=1;i<=m;i++){ 73 scanf("%d%d",&x,&y); 74 init(x+1,y+1,tot+2); 75 init(y+1,x+1,tot); 76 }dfs(s,0); 77 mat z=Pow(a,d+1); 78 printf("%lld\n",z.e[0][2*m+1]); 79 return 0; 80 }