查看: 1499|回復: 0
打印 上一主題 下一主題

[UVa] 104 - Arbitrage

[複製鏈接]
  • TA的每日心情
    鬱悶
    2015-5-15 22:38
  • 簽到天數: 33 天

    [LV.5]常住居民I

    75

    主題

    302

    帖子

    766

    積分

    版主

    TFcis - 105 附設監工官

    Rank: 7Rank: 7Rank: 7

    積分
    766

    台南一中資訊社程式設計達人 - 2014

    跳轉到指定樓層
    樓主
    發表於 2014-5-31 01:51:36 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式

    趕快加入我們來參與討論吧!

    您需要 登錄 才可以下載或查看,沒有帳號?加入我們

    x
    本帖最後由 jd3 於 2014-11-25 14:34 編輯

    題意:給定匯率、求能轉換最少次數、換回原本貨幣的、獲利>=1.01% 的方法


    解析(一個禮拜的心路歷程?)
    首先,他是一張有向圖,沒有回到自己的邊,也沒有重邊
    要找回到自己的路徑(即環),路徑長度 從邊的權重相加 改成 相乘
    然後是判斷路徑大於1.01以及回復路徑


    如果寫過一些有"回到原點"的最短路徑題目
    例如: (痾....不見了)
    對這題的直覺應該就是 Floyd-Warshall (下簡稱FW)的開心 for迴圈*3
    (點的數量也才那麼一點點) (別動 ! 小心 ! )


    把他換成全點對的最小路徑來處理,最小路徑換成>1.01的路線裡面更新最少次的


    怎麼做呢? 首先我們想到要儲存更新次數和儲存路徑,所以開個陣列來存
    for for for 爆下去然後再 for for找了最短的路徑然後再遞迴找答案
    或許你覺得(其實是我以為...)一開始自己到自己設成無限大然後回來看就知道有拿裡有>1.01的環了
    然後就開心的WA
    (不~可能連範測都沒過OAO)


    因為直接FW找出來的答案有點問題 (三層for很爽但是別急別急~)
    首先最容易證明的是一個很容易WA掉的一筆測資(很討厭的)
    他的答案是 1 2 1 2 1
    不~他繞了兩圈!!!
    咱們如果只用2維表格下去存,最後遞迴一定找不出來這條路徑


    其他的錯誤就例如說誤解FW的表格的意義啦~(並不是說不可以有不同解釋)
    更新條件的錯誤啦~(其實我這邊已經錯到很離譜所以接著進入AC解法)



    先來瞭解一下FW
    [C++] 純文本查看 復制代碼
        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];

    當準備更新第k次的時候
    dist[j]存的是只使用了0~(k-1)之中的點當中繼點(經過)的最短距離(不一定有使用(經過))(不經過k~(n-1))
    加入第k個點當作可用的中繼點後如果答案比較好就更新
    (關於原本的FW三維表格請自行google)



    基於剛才發現到的問題,FW不能用了OAO
    因為更新時在原本的矩陣上迭代,資訊被覆蓋了
    所以現在把「更新第P次」拉出第3個維度來開表格
    每次更新時在新的一層上填入,並記錄前一個點


    更新時不使用 if(dist[j] > dist[k]+dist[k][j])
    而是改成 if(dist[j][p] > dist[k][p-1]+dist[k][j][0])
    ( 假設原本的圖存在dist[j][0] )
    請注意紅字的 0
    +dist[k][j][0] 確保更新P次只經過P個點



    見下方code的SP()
    P的for迴圈包在更新外面,表示更新第P次
    更新完立即檢察是否有符合條件的環可以快一些


    雖然此題用這方法不考慮浮點誤差也會AC
    但也可以用log()取值後路徑長就變成用+的,條件變為>= log(1.01)


    [C++] 純文本查看 復制代碼
    /*
        UVA 104
        AC
        56ms
    */
    
    
    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    
    
    
    
    using namespace std;
    
    
    int n;
    double list[32][32][32];    //    [i][j][p] min dist of after
    int through[32][32][32];
    double target = 1.01;
    
    
    
    void recover(int i, int j, int p)
    {
        if(p==0)
            return;
        if(through[i][j][p] != -1)
            recover(i, through[i][j][p], p-1);
        printf("%d ",through[i][j][p]);
    }
    
    void SP()
    {
        for(int p = 1 ; p <= n ; p++)
        {
            //update
            for(int k = 1 ; k <= n ; k++)
                for(int i = 1 ; i <= n ; i++)
                    for(int j = 1 ; j <= n ; j++)
                        if(list[i][k][p-1]*list[k][j][0] > list[i][j][p])
                        {
                            list[i][j][p] = list[i][k][p-1]*list[k][j][0];
                            through[i][j][p] = k;
                        }
                            
                            
            //check
            for(int i = 1 ; i <= n ; i++)
            {
                if(list[i][i][p] >= target)
                {
                    printf("%d ",i);
                    recover(i,i,p);
                    printf("%d\n",i);
                    return;
                }
            }
        }
        
        puts("no arbitrage sequence exists");
        return;
    }
    
    
    int main()
    {
        while(~scanf("%d",&n))
        {
            //init
            memset(list,0,sizeof(list));
            memset(through, -1, sizeof(through));
            
            //input
            for(int i = 1 ; i <= n ; i++)
                for(int j = 1 ; j <= n ; j++)
                    if(i!=j)
                        scanf("%lf", &list[i][j][0]);
                    
            
            SP();
        }
        return 0;
    }
    




    評分

    參與人數 1金幣 +3 收起 理由
    Sylveon + 3 說得好!

    查看全部評分

    <這是個人簽名欄位>
    回復

    使用道具 檢舉

    您需要登錄後才可以回帖 登入 | 加入我們

    本版積分規則

    快速回覆 返回頂部 返回列表