I - Arbitrage (判断是否有大于1的环,用floryd算法,判断大于1的环;)

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美元换0.5英镑,1英镑换10法币,1法币换0.21美元。从1美元出发,兑换过程为:1×0.5×10×0.21=1.05>1,所以该套利交易可行。

ps:以上汇率仅作说明,不代表市场上真正的汇率。

题目分析:按题目意思可以抽象成一个带权有向图求“最长路径”,每次从一个点出发,经过一个环路再回到出发点,实现一次套利交易,所以检查每个点的所有环,直到找到一次可行的套利交易或者全部检查完都没有可行的套利交易。从这个想法出发去找所以的环实现起来很麻烦,所以把问题简化,可以想到,这道题类似求给定节点对的最短路径,那么我们可以借助Floyd算法来实现这一过程,不过需要做一点小小的改动。

//dis[i][j] 表示货币i到货币j的汇率
void init()
{
	for(int i = 1; i <= n; i++)
		for(int j = 1; j <= n; j++)
		{
			if(i == j)
				dis[i][j] = 1.0;//与自身的汇率为1.0
			else
				dis[i][j] = 0.0;//当前i不可交换j
		}
}

对dis数组进行初始化,如果两种货币不能交换,则置dis[i][j]=0.0 相当于最短路径里面置为无穷大,表示i不可到达j。

void Folyd()
{
	for(int k = 1; k <= n; k++)
		for(int i = 1; i <= n; i++)
			for(int j = 1; j <= n; j++)
			{
				if(dis[i][j] < dis[i][k]*dis[k][j])//"松弛操作"
					dis[i][j] = dis[i][k]*dis[k][j];
			}
 
}

Floyd核心代码,注意松弛操作的过程,如果货币i先兑换到货币k,再由货币k兑换到货币j得到的货币更多,那么就进行松弛操作,即dis[i][j] = dis[i][k]*dis[k][j];

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<vector>
#include<string>
#include<map>
#include<queue>
#include<set>
using namespace std;
map<string,int>q;
double mp[50][50];
int main()
{
    int n,m,l=0;
    string s,ss;
    double w;
    while(scanf("%d",&n)&&n)
    {
        int key=0;
        memset(mp,0,sizeof(mp));
        for(int i=0; i<n; i++)
        {
            cin>>s;
            q[s]=i;
            mp[i][i]=1;
        }
        cin>>m;
        for(int i=0; i<m; i++)
        {
            cin>>s>>w>>ss;
            mp[q[s]][q[ss]]=w;
        }
        for(int k=0; k<n; k++)
            for(int i=0; i<n; i++)
                for(int j=0; j<n; j++)
                    mp[i][j]=max(mp[i][j],mp[i][k]*mp[k][j]); // 汇率关系 : j -> k = j -> i * i -> k
 /// 所以说根据佛洛依德的这种关系就可以推出汇率的关系,最后只要判断dist[i][i] 是不是大于1就可以了;
        for(int i=0; i<n; i++)
            if(mp[i][i]>1)
            {
                key=1;
                break;
            }
        printf("Case %d: %s\n",++l,key?"Yes":"No");
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/chen_zan_yu_/article/details/82945035