bnu 4291 Arbitrage?

本文探讨了货币兑换场景下的图论算法应用,通过构建图模型来检测是否存在风险无成本套利机会。利用DFS深度优先搜索算法寻找可能的利润生成路径。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Arbitrage?

Time Limit: 5000ms
Memory Limit: 65536KB
64-bit integer IO format:  %lld      Java class name:  Main
Type: 
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •                   
  • If you are going to travel to the World Finals, you cannot rely on Czech Crowns. You would have to exchange your money for various foreign currencies. This problem deals with multiple currencies and their exchange rates. Your task is to verify that some set of exchange rates is safe, namely detect a possibility of so-called arbitrage.
    An  arbitrage is a risk-free combination of buy and sell operations that gains profit from imbalance in market prices. The prices may apply to various things, typically stock exchange but also currencies.

    Input

    The input consists of several test cases. Each case begins with a line containing one positive integer number  C, 1  ≤ C ≤ 200, the number of currencies.
    The second line of each test case contains  currency codes separated by a space. Each code is composed of 3 uppercase letters and all codes in one test case are different.
    The third line contains one integer number  R, 0  ≤ R ≤ C · ( C − 1), the number of exchange rates available. Each of the following  lines contains one exchange rate in the following format: first currency code, space, second currency code, space, integer number  Ai, colon (“:”), and integer number  Bi. The meaning is as follows: If you pay  Ai units of the first currency, you will get  Bi units of the second currency. You may assume that 1  ≤ Ai,Bi ≤ 100 and that the two currencies are different.

    Output

    For each test case, print one line of output. If there exists any possible sequence of currency exchange operations that would result in a profit, the line should contain the word “Arbitrage”. Otherwise, simply print “Ok”.
    The word  profit in this case means that you start with any amount of any currency and after performing any number of exchanges you will have strictly higher amount of the same currency.

    Sample Input

    2
    CZK EUR
    2
    CZK EUR 25:1
    EUR CZK 1:25
    2
    GBP USD
    2
    USD GBP 8:5
    GBP USD 5:9
    3
    BON DEM CZK
    3
    DEM BON 1:6
    BON CZK 1:5
    DEM CZK 1:20
    3
    CZK EUR GBP
    3
    CZK EUR 24:1
    EUR GBP 5:4
    GBP CZK 1:30
    3
    CZK USD GBP
    4
    CZK USD 28:1
    CZK GBP 31:1
    GBP CZK 1:31
    USD GBP 1:1
    0

    Sample Output

    Ok
    Arbitrage
    Ok
    Ok
    Arbitrage

    题目大意:

    以字符串形式给出的图,两个点之间存在转化率,问存在不存在一种情况形成环并且这个环会让钱变大,就是找最大环,可以用DFS



    #include <bits/stdc++.h>
    using namespace std;
    struct ac
    {
        int h;
        double x,y;//转化率
        ac(int _h=0,double _x=0,double _y=0):h(_h),x(_x),y(_y) {}
    };
    vector<ac> a[222];
    double dp[222];
    bool dfs(int k)//k是满足条件的点
    {
        for(int i=0;i<(int)a[k].size();++i)
        {
            double l=dp[k]*a[k][i].y/a[k][i].x;
            if(dp[a[k][i].h])//当这个点在当前枝杈上被第二次访问
            {
                if(l>dp[a[k][i].h])//比较和他曾经的值
                    return true;
                continue;//不变大继续找和k关联的其他边
            }
            dp[a[k][i].h]=l;
            if(dfs(a[k][i].h))//向下找
                return true;
            dp[a[k][i].h]=0;//清空当前枝杈
        }
        return false;//如果该枝杈无变大的情况
    }
    int main()
    {
        int n,m,i;
        while(cin>>n&&n)
        {
            map<string,int> jb;
            for(i=1;i<=n;++i)//把字符映射成数字
            {
                string s;
                cin>>s;
                jb[s]=i;
                a[i].clear();//在这里就把能用的vector清空
            }
            cin>>m;
            while(m--)
            {
                string s,b;
                double x,y;
                cin>>s>>b;
                scanf("%lf:%lf",&x,&y);
                int z=jb[s];
                int w=jb[b];
                ac adc(w,x,y);
                a[z].push_back(adc);//存图
            }
            bool yes=false;
            for(i=1;i<=n;++i)//每个点当做起点搜一次
            {
                memset(dp,0,sizeof(dp));
                dp[i]=1;
                if(dfs(i))
                {
                    yes=true;
                    break;
                }
            }
            if(yes)
                puts("Arbitrage");
            else
                puts("Ok");
        }
    }
    
    
    这是AC的,再来个WA的

    #include <bits/stdc++.h>
    using namespace std;
    double dp[222];
    int n;
    struct ac
    {
        int x,y;
        double qian,hou;//将字符转换成1-m的数存,qian,hou是转换率
        bool operator < (const ac &b) const
        {
            return x<b.x;
        }
    } a[41111];
    bool dfs(int k)//k是满足的条件的点由K向下找
    {
        ac adc;
        adc.x=k;
        int q=lower_bound(a,a+n,adc)-a;//搜k关联的点,一定是相邻的
        for(int i=q; a[i].x==k; ++i)
        {
            double l=dp[k]*a[i].hou/a[i].qian;
            if(dp[a[i].y])//当这个点在当前枝杈上被第二次访问
            {
                if(l-dp[a[i].y]>1e-6)//比较和他曾经的值
                    return true;
                continue;//不变大继续找和k关联的其他边
            }
            dp[a[i].y]=l;
            if(dfs(a[i].y))//向下找
                return true;
            dp[a[i].y]=0;//清空当前枝杈
        }
        return false;//如果该枝杈无变大的情况
    }
    int main()
    {
        int m,i;
        while(scanf("%d",&m)==1&&m)
        {
            map<string,int> jb;
            for(i=1; i<=m; ++i)
            {
                string s;
                cin>>s;
                jb[s]=i;//把字符映射成1-m
            }
            cin>>n;
            for(i=0; i<n; ++i)
            {
                string s,b;
                double x,y;
                cin>>s>>b;
                scanf("%lf:%lf",&x,&y);
                a[i].x=jb[s];
                a[i].y=jb[b];
                a[i].qian=x;
                a[i].hou=y;
            }
            stable_sort(a,a+n);//排序存图
            bool yes=false;
            for(i=1; i<=m; ++i)
            {
                memset(dp,0,sizeof(dp));
                dp[i]=1;
                if(dfs(i))//分别从m个点搜一次
                {
                    yes=true;
                    break;
                }
            }
            if(yes)
                puts("Arbitrage");
            else
                puts("Ok");
        }
    }



    后面的代码是先前的思路,找了1天错都找不到,于是把二分找点改成邻接表(应该是这个名字吧),用原来的思路就过了,不知道后面的代码那里错了,用二分找图到达的位置为啥不对呢,纠结啊,前后只差个这点。









    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

    当前余额3.43前往充值 >
    需支付:10.00
    成就一亿技术人!
    领取后你会自动成为博主和红包主的粉丝 规则
    hope_wisdom
    发出的红包
    实付
    使用余额支付
    点击重新获取
    扫码支付
    钱包余额 0

    抵扣说明:

    1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
    2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

    余额充值