title: Arbitrage
tags: [acm,杭电,最短路径]
Problem 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 file 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
题意
商品中存在套利机会,对于货币也是一样,根据货币之间的汇率不同,可以经过几次周转,获得利益,比如
一美元 可以兑换 0.5英镑
1英镑可以兑换10法郎
1法郎可以兑换0.21美元
这样1 美元-->0.5英镑--->5法郎---->1.05美元。这样就获益了0.5美元。给你一些国家之间的汇率,问你是否可以实现套利。
分析
最开始看到这个题理解为应该用到所有的汇率关系,这样就成了最小生成树,其实不然,只要存在套利机会就可以,不一定要用到所有的汇率关系,这样就成了最短路径问题,还需注意的是从任意一种货币开始,只要存在套利机会就可以,dijskra算法是单源点最短路径问题,所以不太适用,而Floyd就很适用,当出现i==j时就说明是回到了自身,这是如果road(i)(j)>1的话,说明就有套利的机会,输出yes就行。
代码
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;
double road[101][101];
char name[50][101];
int n;
int getIndex(char *a)
{
for (int i=0; i<n; i++ )
if (strcmp(a,name[i])==0)return i;
}
void floyd()
{
for (int k=0; k<n; k++)
for (int i=0; i<n; i++)
for (int j=0; j<n; j++)
{
if (road[i][j]<road[i][k]*road[k][j])
road[i][j]=road[i][k]*road[k][j];
if(i==j&&road[i][j]>1)//经过一番兑换回到自身,并且获益了。
{
printf("Yes
");
return ;
}
}
printf("No
");
}
int main()
{
int k=1;
while (scanf("%d",&n),n)
{
for (int i=0; i<n; i++)
scanf(" %s",&name[i]);
memset(road,0,sizeof(road));
int m;
scanf("%d",&m);
char a[101],b[101];
double r;
for (int i=0; i<m; i++)
{
scanf(" %s%lf%s",a,&r,b);
road[getIndex(a)][getIndex(b)]=r;
}
printf("Case %d: ",k++);
floyd();
}
return 0;
}
杭电一百道题纪念