经典题目8
hdu 2157 How many ways??
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2157
题目大意:给定一个有向图,问从A点恰好走k步(允许重复经过边)到达B点的方案数mod p的值
把
给定的图转为邻接矩阵,即A(i,j)=1当且仅当存在一条边i->j。令C=A*A,那么C(i,j)=ΣA(i,k)*A(k,j),实际上就
等于从点i到点j恰好经过2条边的路径数(枚举k为中转点)。类似地,C*A的第i行第j列就表示从i到j经过3条边的路径数。同理,如果要求经过k步的
路径数,我们只需要二分求出A^k即可。
代码如下:
1 #include<stdio.h> 2 #include<string.h> 3 #define N 21 4 #define M 1000 5 struct Matrix 6 { 7 int edge[N][N]; 8 }map,res,tmp,map2; 9 int n,m; 10 Matrix mul(Matrix x,Matrix y) //矩阵连乘 11 { 12 int i,j,k; 13 memset(tmp.edge,0,sizeof(tmp.edge)); 14 for(i=0;i<n;i++) 15 for(j=0;j<n;j++) 16 for(k=0;k<n;k++) 17 { 18 tmp.edge[i][j]+=(x.edge[i][k]*y.edge[k][j])%M; 19 tmp.edge[i][j]%=M; 20 } 21 return tmp; 22 } 23 void quickpow(int k) //二进制思想 24 { 25 int i; 26 memset(res.edge,0,sizeof(res.edge)); 27 for(i=0;i<n;i++) //初始化为单位矩阵 28 res.edge[i][i]=1; 29 while(k) 30 { 31 if(k&1) 32 res=mul(res,map2); 33 map2=mul(map2,map2); 34 k>>=1; 35 } 36 } 37 int main() 38 { 39 int i,a,b,k,j,s,e,t; 40 while(scanf("%d%d",&n,&m)!=EOF) 41 { 42 if(n==0&&m==0) 43 break; 44 memset(map.edge,0,sizeof(map.edge)); 45 for(i=0;i<m;i++) 46 { 47 scanf("%d%d",&a,&b); 48 map.edge[a][b]=1; 49 } 50 scanf("%d",&t); 51 while(t--) 52 { 53 scanf("%d%d%d",&s,&e,&k); 54 for(i=0;i<n;i++) 55 for(j=0;j<n;j++) 56 map2.edge[i][j]=map.edge[i][j]; 57 quickpow(k); 58 printf("%d\n",res.edge[s][e]%M); 59 } 60 } 61 return 0; 62 }
poj 3613 Cow Relays
题目链接: http://poj.org/problem?id=3613
题目大意: 给出一张无向连通图,求S到E经过k条边的最短路。
解题思路: 利用递推的思路,先算出经过一条边的最短路,再算两条边......k-1条边,k条边的最短路
先看一下Floyd的核心思想: edge[i][j]=min(edge[i][j],edge[i][k]+edge[k][j])
i到j的最短路是i到j的直接路径或者经过k点的间接路径,但是矩阵的更新总是受到上一次更新的影响
如果每次的更新都存进新矩阵,那么edge[i][k]+edge[k][j]是不是表示只经过三个点两条边的路径呢?
min(edge[i][j],edge[i][k]+edge[k][j])就表示只经过三个点两条边的最短路
方程:F[i][j]m=min(F[i][k]m-1+G[k][j]) {1≤k≤n, m>1}
经过k条边的最短路,那么我们只需要把这个代码重复运行k次
while(k) { res=mul(map,ant); k--; }
这样显然答案是正确的,但是时间复杂度太高O(k*n^3),利用二进制的思想可以把时间复杂度降到O(logK*n^3)
另外,存储边的邻接矩阵map.edge[i][i]不能初始化为0,为0时每次Floyd都会考虑走i--->i这条边,实际上这条边是不存在的
代码如下:
1 //k步最短路 2 #include<stdio.h> 3 #include<string.h> 4 #define INF 0x3f3f3f3f 5 #define N 101 6 struct Matrix 7 { 8 int edge[N][N]; 9 }map,tmp,res; 10 int n,f[N*10]; 11 Matrix mul(Matrix x,Matrix y) //floyd 12 { 13 memset(tmp.edge,INF,sizeof(tmp.edge)); 14 int i,j,k; 15 for(i=1;i<=n;i++) 16 for(j=1;j<=n;j++) 17 for(k=1;k<=n;k++) 18 if(tmp.edge[i][j]>x.edge[i][k]+y.edge[k][j]) 19 tmp.edge[i][j]=x.edge[i][k]+y.edge[k][j]; 20 return tmp; 21 } 22 void quickpow(int k) 23 { 24 int i; 25 memset(res.edge,INF,sizeof(res.edge)); 26 for(i=1;i<=n;i++) 27 res.edge[i][i]=0; 28 while(k) //二进制思想 29 { 30 if(k&1) 31 res=mul(res,map); 32 map=mul(map,map); 33 k>>=1; 34 } 35 } 36 int main() 37 { 38 int i,k,t,s,e,len,u,v; 39 scanf("%d%d%d%d",&k,&t,&s,&e); 40 memset(map.edge,INF,sizeof(map.edge)); 41 memset(f,-1,sizeof(f)); 42 int num=0; 43 for(i=0;i<t;i++) 44 { 45 scanf("%d%d%d",&len,&u,&v); 46 if(f[u]==-1) //离散化 47 f[u]=++num; 48 if(f[v]==-1) //离散化 49 f[v]=++num; 50 map.edge[f[u]][f[v]]=map.edge[f[v]][f[u]]=len; 51 } 52 n=num; 53 quickpow(k); 54 printf("%d\n",res.edge[f[s]][f[e]]); 55 return 0; 56 }