POJ 2240 Arbitrage (spfa判环)

Posted 抓不住Jerry的Tom

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了POJ 2240 Arbitrage (spfa判环)相关的知识,希望对你有一定的参考价值。

Arbitrage
Arbitrage is the use of discrepancies in currency exchange rates to transform one unit of a currency into more than one unit of the same currency. For example, suppose that 1 US Dollar buys 0.5 British pound, 1 British pound buys 10.0 French francs, and 1 French franc buys 0.21 US dollar. Then, by converting currencies, a clever trader can start with 1 US dollar and buy 0.5 * 10.0 * 0.21 = 1.05 US dollars, making a profit of 5 percent. 

Your job is to write a program that takes a list of currency exchange rates as input and then determines whether arbitrage is possible or not. 

Input

The input will contain one or more test cases. Om the first line of each test case there is an integer n (1<=n<=30), representing the number of different currencies. The next n lines each contain the name of one currency. Within a name no spaces will appear. The next line contains one integer m, representing the length of the table to follow. The last m lines each contain the name ci of a source currency, a real number rij which represents the exchange rate from ci to cj and a name cj of the destination currency. Exchanges which do not appear in the table are impossible. 
Test cases are separated from each other by a blank line. Input is terminated by a value of zero (0) for n.

Output

For each test case, print one line telling whether arbitrage is possible or not in the format "Case case: Yes" respectively "Case case: No".

Sample Input

3
USDollar
BritishPound
FrenchFranc
3
USDollar 0.5 BritishPound
BritishPound 10.0 FrenchFranc
FrenchFranc 0.21 USDollar

3
USDollar
BritishPound
FrenchFranc
6
USDollar 0.5 BritishPound
USDollar 4.9 FrenchFranc
BritishPound 10.0 FrenchFranc
BritishPound 1.99 USDollar
FrenchFranc 0.09 BritishPound
FrenchFranc 0.19 USDollar

0

Sample Output

Case 1: Yes
Case 2: No

给你一个汇率表,找出其中有没有一种能创造无限金钱的环?这是我第一次写的比较清醒的spfa。
spfa判环有两种:
1.dfs:判断某个点是否在同一条路径出现多次
2.bfs:判断某个点入队的次数是否大于自身的入度
代码如下:
  1 #include <iostream>
  2 #include <queue>
  3 #include <cstdio>
  4 #include <cstring>
  5 #include <string>
  6 #include <algorithm>
  7 #include <map>
  8 #include <vector>
  9 using namespace std;
 10 #define M 9000
 11 map <string,int> money;//将货币映射成数字
 12 struct Edge
 13 {
 14     int u,v;
 15     double rate;
 16 }edge[M];
 17 vector <int> g[50];//存图
 18 bool inque[50];//标记是否入队
 19 double price[50];//到达某点的最大汇率(类似距离)
 20 int cnt[50];//标记点的入队次数
 21 int in_degree[50];//入度
 22 int toNum (string x)
 23 {
 24     return money[x];
 25 }
 26 int n,m;
 27 void init()
 28 {
 29     for (int i=0;i<50;++i){
 30         inque[i]=false;
 31         price[i]=0;
 32         cnt[i]=0;
 33     }
 34 }
 35 bool spfa(int x)
 36 {
 37     queue<int>q;
 38     cnt[x]++;
 39     price[x]=1.0;
 40     inque[x]=true;
 41     q.push(x);
 42     while (!q.empty()){
 43         int now=q.front();
 44         q.pop();
 45         inque[now]=false;
 46         for (int i=0;i<g[now].size();++i){
 47             int e=g[now][i];
 48             int nxt=edge[e].v;
 49             if (price[nxt]<price[now]*edge[e].rate){
 50                 price[nxt]=price[now]*edge[e].rate;//松弛
 51                 if (!inque[nxt]){
 52                     inque[nxt]=true;
 53                     q.push(nxt);
 54                     if (++cnt[nxt]>in_degree[nxt]){//某点的入队次数大于它的入度
 55                         return true;
 56                     }
 57                 }
 58             }
 59         }
 60     }
 61     return false;
 62 }
 63 int main()
 64 {
 65     //freopen("de.txt","r",stdin);
 66     int casee=0;
 67     while (~scanf("%d",&n)){
 68         if (n==0) break;
 69         money.clear();
 70         for(int i=0;i<50;++i)
 71             g[i].clear();
 72         for (int i=0;i<50;++i)
 73             in_degree[i]=0;
 74         for (int i=0;i<n;++i){
 75             string mny;
 76             cin>>mny;
 77             money[mny]=i;
 78         }
 79         scanf("%d",&m);
 80         for (int i=0;i<m;++i){
 81             string a,b;
 82             double x;
 83             cin>>a>>x>>b;
 84             edge[i].u=toNum(a);
 85             edge[i].v=toNum(b);
 86             edge[i].rate=x;
 87             g[edge[i].u].push_back(i);
 88             in_degree[edge[i].v]++;
 89         }
 90         bool ok=false;
 91         for (int i=0;i<n;++i){//从每个点跑spfa
 92             init();//记得每次初始化
 93             if (spfa(i)){
 94                 ok=true;
 95                 break;
 96             }
 97         }
 98         if (ok)
 99             printf("Case %d: Yes\n",++casee);
100         else
101             printf("Case %d: No\n",++casee);
102     }
103     return 0;
104 }

这题813ms过的...folyd好像只要几十ms,就当练习spfa了。



以上是关于POJ 2240 Arbitrage (spfa判环)的主要内容,如果未能解决你的问题,请参考以下文章

POJ 2240 Arbitrage(SPFA+邻接矩阵)

[ An Ac a Day ^_^ ][kuangbin带你飞]专题四 最短路练习 POJ 2240 Arbitrage spfa求负环

用SPFA 解决POJ2240

POJ 2240 Arbitrage

poj2240Arbitrage

POJ2240:Arbitrage(最长路+正环)