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 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

题意:

已知n种货币,以及m种货币汇率及方式,问能否通过货币转换,使得财富增加。

解题思路:

目测是一条不错的生财之道~~~(打住)

财富增加的话肯定是以同种货币作比较,否则没有意义,因此题意大致可以变成在一个n个顶点的图中能否找到一个正权环,这里的正权环指财富增加,很明显可用Bellman-ford 算法(专门解决存在环的最短路径问题)。

Bellman-ford 算法:一个具有n个顶点的图如果不存在环,则从顶点x,到顶点y,最多经过n-1条边(要考虑连通性,每个顶点最多经过 1 次),因此 x 到 y 的最短路 最多经过 n - 1 次松弛操作(就是更新长度)就应该出现,如果第 n 次松弛还可以得到最优,那么这个图就肯定是存在环了(直接用Dijkstra 就无法得到最优的,环的存在会影响最优解是否存在)。

这里给的顶点时货币的英文名,为了方便简洁,用map 将货币名 与 编号一一对应

此题有多种解法,注意到顶点最大为30(限制很小,不愧是模板练习题),可用Floyd算法求出整个图的最短路,注意此处并不是真正的最短路,但通过插点,即 i -> j 能否改成 i -> k -> j 的路,就会把环给考虑至少一次,那么对应的 path[i][i] 也就是本金肯定是增加的(相对于初值),为了方便,将本金设为 1 .

C++版本一

Bellman_ford

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <algorithm>
#include<set>
#include<vector>
#include<map>

#define INF 0x3f3f3f3f
using namespace std;
int t,n,m;

map<string ,int> m0;

double r;
double dist[200];

struct node
{
    int a,b;
    double r;
    node(int sst,int eed,double rtt) : a(sst),b(eed),r(rtt) {}
    node() {}

};
vector<node> G;
bool Bellman_ford(int v)
{
    memset(dist,0,sizeof(dist));
    dist[v] = 1;
    for(int j = 1;j < n;j++) {  // n - 1 次松弛操作
        for(int i = 0;i <G.size();i++) {
            int p1 = G[i].a,p2 = G[i].b;
            if(dist[p2] < dist[p1] * G[i].r) { //尝试更新顶点 v 到 p2 的距离
                dist[p2] = dist[p1] * G[i].r;
            }
        }
    }
    for(int i = 0;i < G.size();i++){
        int p1 = G[i].a,p2 = G[i].b;
        if(dist[p2] < dist[p1] * G[i].r) { //第 n 次松弛可以得到更优解,则存在环
            return true;
        }
    }
    return false;
}

int main()
{
    t=0;
    while(~scanf("%d",&n)){
        if(n==0)    break;
        t++;
        char tempchar1[100],tempchar2[100];
        for(int i=0;i<n;i++){
            scanf("%s",tempchar1);
            m0[tempchar1] = i;
        }
        scanf("%d",&m);

        G.clear();
        for(int i=1;i<=m;i++){
            scanf("%s %lf %s",tempchar1,&r,tempchar2);

            G.push_back( node(m0[tempchar1],m0[tempchar2],r) );
        }
        for(int i=0;i<n;i++){
        if(Bellman_ford(i)){
            printf("Case %d: Yes\n",t);
            break;
        }
        else if(i==n-1)
            printf("Case %d: No\n",t);
        }
    }
    //cout << "Hello world!" << endl;
    return 0;
}

C++版本二

Floyd 

//floyed
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<iostream>
#include<vector>
#include<map>
 
using namespace std;
int n,m;
double dist[40][40];
map<string,int> money;
 
void init()
{
    for(int i = 0;i < n;i++) {
        for(int j = 0;j < n;j++){
            if(i == j) dist[i][j] = 1;
            else dist[i][j] = 0;
        }
    }
}
 
void floyd()
{
    for(int k = 0;k < n;k++) {
        for(int i = 0;i < n;i++) {
            for(int j = 0;j < n;j++) {
                if(dist[i][j] < dist[i][k] * dist[k][j])
                    dist[i][j] = dist[i][k] * dist[k][j];
            }
        }
    }
}
 
int main()
{
    int cas = 1;
    string s,ss;
    double r;
    while(~scanf("%d",&n) &&n) {
        init();
        for(int i = 0;i < n;i++) {
            cin >> s;
            money[s] = i;
        }
        cin >> m;
 
        for(int i = 0;i < m;i++) {
            cin >> s >> r >> ss;
            dist[money[s] ][money[ss] ] = r;
        }
        floyd();
        printf("Case %d: ",cas++);
        for(int i = 0;i < n;i++) {
            if(dist[i][i] > 1) {
                cout << "Yes" << endl;
                break;
            }
            else if(i == n - 1)
                cout << "No" <<endl;
        }
    }
    return 0;
}

C++版本三 

Floyd 

#include <iostream>
#include <map>
#include <cstring>
#include <string>
using namespace std;
 
int main()
{
    double e[35][35];
    int n;
    map<string,int>exchange_rate;
int num=0;
    while (cin>>n&&n!=0)
    {
 
 
        memset(e,0,sizeof(e));
        for(int i=1; i<=n; i++)
            e[i][i]=1;
 
        num++;
        int p=1;
        string currency ;
        for(int i=0; i<n; i++)
        {
            cin >>currency;
            exchange_rate.insert(make_pair(currency,p++));  
        }
 
        int m;
        cin >>m;
        for(int i=0; i<m; i++)
        {
            string a,c;
            double b;
            cin >>a>>b>>c;
 
            e[exchange_rate[a]][exchange_rate[c]]=b;
        }
 
        for(int k=1; k<=n; k++)
            for(int i=1; i<=n; i++)
                for(int j=1; j<=n; j++)
                    if(e[i][j]<e[i][k]*e[k][j])
                        e[i][j]=e[i][k]*e[k][j];
        int cis=0;
        for(int i=1; i<=n; i++)
            if(e[i][i]>1)
            {
                cis++;
            }
 
        if(cis==0)
            cout <<"Case "<<num<<": No"<<endl;
        else
            cout <<"Case "<<num<<": Yes"<<endl;
 
            exchange_rate.clear();
 
    }
 
    return 0;
}

C++版本四

SPFA

#include<iostream>
using namespace std;
#include<string.h>
#include<stdio.h>
#include<queue>
#define maxn 0x7fffffff
#include<map>
int n,m,f;
double dis[3000];
int vis[3000],head[3000];
struct node
{
    double w;
    int e,next;
}edge[3000];
void add(int s,int e,double w)
{
    edge[f].e=e;
    edge[f].w=w;
    edge[f].next=head[s];
    head[s]=f++;
}
int spfa(int s)
{
    int cur,k,i;
    queue<int>q;
    while(!q.empty())
    {
        q.pop();
    }
    q.push(s);
    dis[s]=1;
    vis[s]=1;
    while(!q.empty())
    {
        cur=q.front();
        q.pop();
        vis[cur]=0;
        for(i=head[cur];i!=-1;i=edge[i].next)
        {
            k=edge[i].e;
           if(dis[k]<dis[cur]*edge[i].w)
           {
               dis[k]=dis[cur]*edge[i].w;
               if(!vis[k])
               {
                   q.push(k);
                   vis[k]=1;
               }
           }
           if(dis[s]>1)
            return 1;
        }
    }
    return 0;
}
int main()
{
     int i,j=1;
     double w;
     char s[100],s1[100],s2[100];
     map<string,int>v;
     while(cin>>n)
     { if(n==0)break;
         f=0;
         memset(vis,0,sizeof(vis));
         memset(head,-1,sizeof(head));
     for(i=0;i<100;i++)
        dis[i]=0;
     for(i=1;i<=n;i++)
     {
         cin>>s;
         v[s]=i;
     }
      cin>>m;
      for(i=0;i<m;i++)
      {
          cin>>s1>>w>>s2;
          add(v[s1],v[s2],w);
      }
      cout<<"Case "<<j<<": ";
      for(i=1;i<=n;i++)
      {
          if(spfa(i))
         {
            cout<<"Yes\n";
            break;
         }
      }
      if(i==n+1)
      cout<<"No\n";
        j++;
     }
    return 0;
}

 

全部评论

相关推荐

小红书 后端开发 总包n+8w+期权
点赞 评论 收藏
分享
已老实求offer😫:有点像徐坤(没有冒犯的意思哈)
点赞 评论 收藏
分享
Yushuu:你的确很厉害,但是有一个小问题:谁问你了?我的意思是,谁在意?我告诉你,根本没人问你,在我们之中0人问了你,我把所有问你的人都请来 party 了,到场人数是0个人,誰问你了?WHO ASKED?谁问汝矣?誰があなたに聞きましたか?누가 물어봤어?我爬上了珠穆朗玛峰也没找到谁问你了,我刚刚潜入了世界上最大的射电望远镜也没开到那个问你的人的盒,在找到谁问你之前我连癌症的解药都发明了出来,我开了最大距离渲染也没找到谁问你了我活在这个被辐射蹂躏了多年的破碎世界的坟墓里目睹全球核战争把人类文明毁灭也没见到谁问你了😆
点赞 评论 收藏
分享
如题如果提出了一个薪资,A不成功,会有可能被取消offer吗
爱打瞌睡的柯基:最想去你们公司 但是别家开的高一些,希望能申请高一点 不管结果如何都谢谢你
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务