首页 > 代码库 > POJ 2240 - Arbitrage(最短路)

POJ 2240 - Arbitrage(最短路)

题意:

给出一些货币和货币之间的兑换比率,问是否可以使某种货币经过一些列兑换之后,货币值增加。

举例说就是1美元经过一些兑换之后,超过1美元。可以输出Yes,否则输出No。

 

分析:

首先我们要把货币之间的关系转化成一张图。转化时,用STL里面的map很方便。

为每种货币分配一个序列号,一个序列号代表了一个图中间的NODE,而node之间的edge用汇率表示。

 

一开始用Dijkstra算法做,死活AC不了,网友给的理由是:

由于Dijkstra算法不能处理带有负权值的最短路,但此题中,两种货币之间的兑换比率可能小于1,相当于这条路径的权值为负

前车之鉴,WA的代码:

 1 #include<iostream> 2 #include<cstdio> 3 #include<queue> 4 #include<string.h> 5 #include<string> 6 #include<map> 7 using namespace std; 8 #define maxn 31 9 #define inf 0x3f3f3f3f10 double edges[maxn][maxn];11 double dist[maxn];12 typedef pair<int,int> P;13 void init(){14     for(int i=1;i<maxn;i++)15         for(int j=1;j<maxn;j++)16             edges[i][j]=(i==j?1:0);//1代表等价价换,0:代表无法交换17 }18 19 void dijkstra(int s,int n){20     bool visited[maxn];21     memset(visited,0,sizeof(visited));22     visited[s]=true;23     for(int i=1;i<=n;i++)24         dist[i]=edges[s][i];25     for(int i=1,u;i<=n;i++){26         double max=-1;27         for(int j=1;j<=n;j++)28             if(!visited[j]&&dist[j]>max){29                 max=dist[j]; u=j;30             }31         32         visited[u]=true;33         for(int j=1;j<=n;j++){34             if(dist[u]*edges[u][j]>dist[j])35                 dist[j]=dist[u]*edges[u][j];36         }37     }38 }39 40 int main(){41     //freopen("in.txt","r",stdin);42     int n,cases=0;43     while(scanf("%d",&n)!=EOF && n){44         cases++;45         init();46         map<string,int> ma;47         string s,t;48         for(int i=1;i<=n;i++){49             cin>>s;50             ma.insert(make_pair(s,i));51         }52         int m;53         double tmp;54         scanf("%d",&m);55         while(m--){56             cin>>s>>tmp>>t;57             edges[ma[s]][ma[t]]=tmp;58         }59 60         dijkstra(1,n);61         printf("Case %d: ",cases);62         if(dist[1]>1.0)63             printf("Yes\n");64         else 65             printf("No\n");66     }67 }

 

最后写了一个Floyd的代码版本,结果一下子就过了,我只能默默的哭了

 1 #include<iostream> 2 #include<cstdio> 3 #include<queue> 4 #include<string.h> 5 #include<string> 6 #include<map> 7 using namespace std; 8 #define maxn 31 9 #define inf 0x3f3f3f3f10 double edges[maxn][maxn];11 void init(){12     for(int i=1;i<maxn;i++)13         for(int j=1;j<maxn;j++)14             edges[i][j]=(i==j?1:0);//1:代表等价交换,0:代表无法交换15 }16 17 void floyd_warshall(int s,int n){18     for(int k=1;k<=n;k++){19         for(int i=1,u;i<=n;i++){20             for(int j=1;j<=n;j++){21                 if(edges[i][k]*edges[k][j]>edges[i][j])//如果找到了更好的交换方案22                     edges[i][j]=edges[i][k]*edges[k][j];23             }24         }25     }26 }27 28 int main(){29     //freopen("in.txt","r",stdin);30     int n,cases=0;31     while(scanf("%d",&n)!=EOF && n){32         cases++;33         init();34         map<string,int> ma;35         string s,t;36         for(int i=1;i<=n;i++){37             cin>>s;38             ma.insert(make_pair(s,i));39         }40         int m;41         double tmp;42         scanf("%d",&m);43         while(m--){44             cin>>s>>tmp>>t;45             edges[ma[s]][ma[t]]=tmp;46         }47 48         dijkstra(1,n);49         printf("Case %d: ",cases);50         /*for(int i=1,u;i<=n;i++){51             for(int j=1;j<=n;j++){52                 printf("%.2f  ",edges[i][j]);53             }54             printf("\n");55         }*/56         if(edges[1][1]>1.0)57             printf("Yes\n");58         else 59             printf("No\n");60     }61 }

 

【问题】:Folyd算法能处理包含负权边的图吗?

       答案是可以的。Floyd-Warshall算法和Bellman-Ford算法一样,可以处理边是负数的情况。

                                                                                                           ---《挑战程序设计竞赛》 P.103

 

POJ 2240 - Arbitrage(最短路)