【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 }
View Code

 

posted @ 2017-11-05 08:42  鲸头鹳  阅读(175)  评论(0编辑  收藏  举报