Bellman-ford算法 poj2240
Bellman-ford算法的递推公式应该改为(求源点v0到各顶点v的最短路径):
初始:dist(0)[v]=inf,dist(0)[v0]=0,v0是源点,v≠v0
递推:对每条边(u,v),dist(k)[v]=min{dist(k-1)[v],dist(k-1)[v]+w(u,v)};k=1,2,3...
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 void bellman(int v0){ 2 int i,k; 3 for(i=0;i<n;i++){ 4 dist[i]=inf; 5 path[i]=-1; 6 } 7 dist[v0]=0; 8 for(k=1;k<n;k++){ 9 for(i=0;i<m;i++){ 10 if(dist[edges[i].u]!=INF&&edges[i].w+dist[edge[i].u]<dist[edges[i].v]){ 11 dist[edges[i].v]=edges[i].w+dist[edge[i].u]; 12 path[edges[i].v]=edges[i].u; 13 } 14 } 15 } 16 }
Bellman-ford算法判断负权值回路:
如果存在负权值回路,则最短路径不存在,因为可以重复走这个回路使得路径无穷小,在Bellman-ford算法中,判断是否存在从源点可达的负权值回路的方法如下:
再求出dist(n-1)[v]之后,再对每一条边<u,v>判断一下:加入这条边会不会使得顶点v的最短路径再缩小,即判断
dist[u]+edge[u][v]<dist[v]
是否成立,如果成立,则说明存在从源点可达的负权值回路。
代码如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 for(i=0;i<n;i++){ 2 for(j=0;j<n;j++){ 3 if(edge[i][j]<inf&&dist[i]+edge[i][j]<dist[j]) 4 return 0; 5 } 6 } 7 return 1; 8 ///或者是以下代码 9 for(i=0;i<m;i++){ 10 if(dist[edge[i].u]!=inf&&edge[i].w+dist[edge[i].u]<dist[edge[i].v]) 11 return 0; 12 } 13 return 1;
Bellman-ford算法与Dijkstra算法相比,可以处理有负权值的边的最短路问题,在求解过程中的区别是:
①Dijkstra在求解过程中,源点到集合S内各顶点的最短路径一旦求出,则不变化了,修改的仅仅是从源点到T集合中个顶点的最短路径长度。
②Bellman-ford算法在求解过程中,每次循环每个顶点的dist[]值都有可能要修改,也就是说源点到各顶点最短路径长度一直要到Bellman-ford算法结束才确定下来。
poj2240题意:比如1美元可以兑换0.5英镑,1英镑可以兑换10.0法郎,1法郎可以兑换0.21美元,这样1美元可以转换成1*0.5*0.21=1.05美元,给出兑换率,算出是否存在这种Arbitrage。
思路:求到本身的最长路,可以用floyd,也可以用Bellman-ford~
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <map> 2 #include <string.h> 3 #include <stdio.h> 4 #include <iostream> 5 using namespace std; 6 const int N=40; 7 int n,m,flag; 8 double dist[N]; 9 struct edge{ 10 int a,b; 11 double c; 12 }e[N*N]; 13 void bellman(int v0){ 14 int i,k; 15 memset(dist,0,sizeof(dist)); 16 dist[v0]=1; 17 for(k=1;k<=n;k++){ 18 for(i=0;i<m;i++){ 19 if(dist[e[i].a]*e[i].c>dist[e[i].b]){ 20 dist[e[i].b]=dist[e[i].a]*e[i].c; 21 } 22 } 23 } 24 if(dist[v0]>1.0) flag=1; 25 } 26 int main(){ 27 char ch[100]; 28 int i,j,k=0; 29 while(scanf("%d",&n)!=EOF&&n){ 30 map<string,int>M; 31 for(i=0;i<n;i++){ 32 scanf("%s",ch); 33 M[ch]=i; 34 } 35 scanf("%d",&m); 36 for(i=0;i<m;i++){ 37 scanf("%s %lf",ch,&e[i].c); 38 e[i].a=M[ch]; 39 scanf("%s",ch); 40 e[i].b=M[ch]; 41 } 42 flag=0; 43 for(i=0;i<n;i++){ 44 bellman(i); 45 if(flag) break; 46 } 47 printf("Case %d: ",++k); 48 if(flag) puts("Yes"); 49 else puts("No"); 50 } 51 return 0; 52 }