1. 程式人生 > >POJ2240:Arbitrage(最長路+正環)

POJ2240:Arbitrage(最長路+正環)

之間 ack inf sample idt double con tis accep

Arbitrage

Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 29374 Accepted: 12279

題目鏈接:http://poj.org/problem?id=2240

Description:

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

題意:

給出幾種貨幣單位,以及貨幣與貨幣之間的兌換匯率,問最後是否能夠套利。就是用1個單位的貨幣,不斷去兌換其它的貨幣,最後得到大於1個單位的相應貨幣。

題解:

總的思路就是跑最長路看看是否有正環吧,有的話就說明至少存在一種貨幣可以用來套利。

這裏跑最長路的時候要把之前的“ + ”改造為“ * ”,至於正確性,乘法取個對數也等價於加吧?具體證明我也不是很清楚。

代碼如下:

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <queue>
#include <cmath>
#include <map>
#include <string>
#include <stack>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int N = 35;
map <string ,int> mp;
int n,num;
struct Edge{
    int u,v,next;
    double w;
}e[N*N<<1];
int head[N],vis[N],c[N];
int tot;
void adde(int u,int v,double w){
    e[tot].v=v;e[tot].w=w;e[tot].next=head[u];head[u]=tot++;
}
double d[N];
int spfa(int s){
    memset(d,0,sizeof(d));memset(vis,0,sizeof(vis));
    d[s]=1;queue <int> q;q.push(s);memset(c,0,sizeof(c));
    c[s]=1;vis[s]=1;
    while(!q.empty()){
        int u=q.front();q.pop();vis[u]=0;
        for(int i=head[u];i!=-1;i=e[i].next){
            int v=e[i].v;
            if(d[v]<d[u]*e[i].w){
                d[v]=d[u]*e[i].w;
                if(!vis[v]){
                    vis[v]=1;
                    q.push(v);
                    if(++c[v]>n) return 1;
                }
            }
        }
    }
    return 0;
}
int main(){
    int cnt =0;
    while(scanf("%d",&n)!=EOF){
        if(n==0) break ;
        string s;
        num=0;cnt++;
        for(int i=1;i<=n;i++){
            cin>>s;
            mp[s]=++num;
        }
        int tmp;
        scanf("%d",&tmp);
        memset(head,-1,sizeof(head));tot=0;
        for(int i=1;i<=tmp;i++){
            string s1,s2;
            double w;
            cin>>s1>>w>>s2;
            adde(mp[s1],mp[s2],w);
        }
        printf("Case %d: ",cnt);
        if(spfa(1)) puts("Yes");
        else puts("No");
    }
    return 0;
}

POJ2240:Arbitrage(最長路+正環)