跳到主要內容

[ACM] Some hints about uva 104 (Modified Floyd-Warshall)

by gits
Original Thread http://online-judge.uva.es/board/viewtopic.php?t=7292

Well, I'll assume you understand what the problem asks. You have to find the shortest sequence that yelds a profit (not the one with the greatest profit!). If there is more then one sequence with the same length, any of those is valid.

Now, you can't just try with brute force (trying all combinations) because it'll be too slow and you'll get Time Limit Exceeded. However, there's a well known algorithm, Floyd-Warshall, which will find all the shortest paths between every node to the others in just O(n^3) time. You can find more info about F-W in the net. In my previous post I said how you have to change the general F-W algorithm to work for this particular problem...

As for floating point errors, most numbers representation isn't totally acurate; for instance, 0.1 is usually stored as 0.10000000000000001. After some operations, the error may influence the final result. Again, search the net for floating point errors. However, you won't have to deal with these errors to solve this problems (at least I didn't).

Hope this helps


=================================
Floyd-Warshall finds all the mininum paths between every vertex and all the other vertexes. However, in this problem you not only have to find the shortest path, it also has to make a profit of more than 1%.

Simple F-W goes like this:
// initialization
for (i = 0; i < n; i++) {
    for (j = 0; j < n; j++) {
      best[i][j] = path[i][j];
      path[i][j] = i;
    }
}

for (k = 0; k < n; k++) {
    for (i = 0; i < n; i++) {
        for (j = 0; j < n; j++) {
            if (best[i][k] + best[k][j] < best[i][j]) {
                best[i][j] = best[i][k] + best[k][j];
                path[i][j] = k;
            }
        }
   }
}

For this problem, instead of having best[i][j] and path[i][j] I have best[i][j][s] and path[i][j][s], which means "best path from i to j in s steps". I also have an outer loop, representing the number of steps.
// initialization
best[i][j][s] = 0, for all i,j,s
best[i][j][1] = input for the program
best[i][i][1] = 1, for all i
path[i][j][1] = i, for all i, j

for (steps = 2; steps <= n; steps++)
    for k...
        for i..
            for j..
                tmp = best[i][k][steps-1] * best[k][j][1]
                if (tmp > best[i][j][steps]) {
                    best[i][j][steps] = tmp;
                    path[i][j][steps] = k;
                }
What we are doing is to find the most profitable way to go from i to j in "steps" steps, trying for each to use k as the point just before j. As you can see, this is O(n^4) but since max n is 20 it's ok.

After this, you scan though best[i][i][s] (best way to go from i to i again, in s steps). Remember that you want the minimum number of steps that yields a profit; so it's this:
for (steps = 2; steps <= n; steps++)
    for (i = 0; i < n; i++)
        if (best[i][i][steps] > 1.01) {
            // score!
        }
If the "if" never matches, then there is no arbitrage sequence. If it matches, you have to print the path. To print the path, use path[i][i][steps], which is the vertex just before the last (i).

For instance, if i is 1 and steps is 4. Check path[1][1][4]. Suppose it is 2. So the path ends with "... 2 1". Now check path[1][2][3]. Supposing it's 4, the path ends with "... 4 2 1". Now check path[1][4][2]. If it's 5, the path is "... 5 4 2 1". Finally check path[1][5][1], which will be obviously 1. So the complete path is "1 5 4 2 1" (exactly 4 steps).

Just remember that path[i][j][s] is the vertex which is before the last one in a path from i to j in s steps. If s is 1, the path is simply "i j". In this problem you have to start and finish in the same currency; that's why we only search in best[i][i][steps].

Hope this helps, I almost wrote the complete program!

You could also stop the algorithm as soon as you found a solution. In other posts, some people talked about a O(n^3) solution but I can't figure it out... if someone has such a solution please mail it to me, I would love to learn how to do this in a better way.

Good luck and happy coding!

留言

這個網誌中的熱門文章

讀書心得: 你以為你以為的就是你以為的嗎?

當初想要接觸哲學的時候,挑上的第一本書就是「你以為你以為就是你以為的嗎?」,因為書名太好玩了。讀完後發現內容也一樣好玩,整本書的形式有點像坊間流行的心理測驗小書,每章的開頭都要讀者先做一組題目,後面接著就對你的答案做一番分析。 我自己的讀後感是,恩,這些題目對一個以前從未接觸過哲學的人來說太過犀利,第一次作答的時候,每翻過一頁都好像在呼自己巴掌,臉頰很燙。 「你以為你以為就是你以為的嗎?」書名念起來很拗口,但是很貼切,因為這些題目為的是要檢查我們腦袋內的想法是否一致,在邏輯上有沒有BUG。 我舉個例子,書裡有道題目「只要不傷害他人,任何人都有權自由追求自己的目標」要讀者回答同不同意,我認為這句話聽起來相當合理,所以勾了同意。過了幾題後,出現另一道題目是「為個人吸食而持有毒品的行為應予除罪化」,這次我的直覺是毒品這麼危險,怎麼可以除罪化呢,馬上勾不同意。 但是,我沒有發現這是刻意安排的陷阱,因為這兩句話其實講的是同一回事。 單純個人持有毒品,不散佈也不販賣,就不算傷害他人,那他就應該有自由追求自己的「吸食毒品」目標的權利,畢竟他只有傷害自己呀。這敘述聽起來有點危險,不過我必須承認一開始的確想的不夠清楚,我以為第一句話是真理,但馬上被反例打了自己的臉。 再舉一個例子,首先是「對藝術品的評斷,純粹是個人品味的問題」,接著是「米開朗基羅是史上數一數二的偉大藝術家」,這牽涉到評斷藝術的標準,不過你只能認同兩句話的其中之一。 書中我最有興趣的是「神明DIY工作室」與「信仰殺戮戰場」,這兩章擺明了直衝基督徒而來。當中有些問題圍繞著以下的敘述,如果你同意「神是全知、全能、又全然慈愛」,那該怎麼解釋世界上發生的許多苦難呢? 比如說被南亞海嘯淹沒的小女孩? 如果神沒辦法消除這些苦難,祂就不是全能。如果神沒辦法事先知道創造出來的世界會有這些苦難,祂就不是全知。如果神明知道有苦難,也有能力去掉,但是卻故意不做,那祂就不是全然慈愛。 我思考後的結論是,全然慈愛的神並不等於神希望世上的苦難越少越好,這些苦難都是在祂的允許下發生的。 書裡指出了一個基督徒的通病,被問倒了之後就嚷嚷「你不知道神是超越人所理解的嗎 」,但回頭又馬上賦予神非常明確地人的屬性。後來我也理解到這些尖銳的問題並不是故意要為難我對神的看法,而是逼迫我去反思一些比較深層的宗教議題,就像我...

[ACM] 自己整理一些有用的網站

=解題提示= UVa官方論壇: 全世界UVa討論的集散地,當你題目解不出來時,第一件事就該來這裡搜尋該題目的討論串,通常會找到很多好心人提供的測資跟提示。 Methods to Solve 全世界最大的UVa解題提示網站,收錄的題目數量很多,品質也不錯。 Algorismist 這是一個關於演算法的維基網站,也有收錄 UVa 的解題提示,如果你有能力可以參與編輯條目,讓它變得更好。 UVa Toolkit 一般來講UVa題目頁上的範例測資都太簡單,聊勝於無。而 UVa Toolkit 這工具恰好補足了這方面的缺憾,你可以餵給它任何測資,並取得正確的對應輸出,對釐清題意很有幫助。 uHunt 非常非常好用的 UVa 解題工具網頁,可以很輕鬆的搜尋題目,安排自己解題的方向,瀏覽自己過去的解題紀錄等等。 =題目中譯= Lucky貓 著名的ACM題目中譯網,及解題提示。 Lucky貓Mirror站 同上,有難度提示。 ACM中譯 少量題目中譯。 ZeroJudge ZeroJudge是非常優秀的國產程式解題網,裡面有一區專門收錄UVa題目中譯。 =算法教學= DJWS的網路日誌 資源豐富的網站,整理了很多的算法教學,以及各種ACM競賽的資料。 C語言考古題 & C的解題 大量題目教學 Art of Programming Contest for uva 淺顯的ACM入門書,免費線上版。 NACOW 對岸關於程式設計與解題的wiki Infinite Loop 提供許多教學及ACM Tips, Sources。 =API Reference= Cplusplus.com 簡潔清楚的C/C++標準函式參考手冊,範例碼清楚實用,值得看看,我自己把這兒當後花園逛了。 =題目列表= ACM熱題排行榜 芭樂題排行榜,有哪些熱門題你還沒解過呢XD =討論論壇= NPSC補完計畫 針對NPSC的解題網站 OIBH 對岸關於資訊奧林匹亞競賽討論的論壇 algogeeks Google group about algorithms. =解題強者= 這部分網站就請各位審慎參觀了,大部分ACMer的程式碼都寫得不太好讀。 心如止水 350+題目解答,有基本的...