[動態規划]石子合並問題


https://acm.sdut.edu.cn/onlinejudge2/index.php/Home/Contest/contestproblem/cid/3016/pid/1729

石子合並問題

Time Limit: 1000 ms Memory Limit: 65536 KiB
 

Problem Description

在一個圓形操場的四周擺放着n堆石子。現要將石子有次序地合並成一堆。規定每次只能選相鄰的2 堆石子合並成新的一堆,並將新的一堆石子數記為該次合並的得分。試設計一個算法,計算出將n堆石子合並成一堆的最小得分和最大得分。
對於給定n堆石子,計算合並成一堆的最小得分和最大得分。

Input

輸入數據的第1行是正整數n,1≤n≤100,表示有n堆石子。第二行有n個數,分別表示每堆石子的個數。

Output

輸出數據有兩行,第1行中的數是最小得分,第2行中的數是最大得分。

Sample Input

4
4 4 5 9

Sample Output

43
54

算法考試考完了(題目有點簡單僥幸AK..),但這個問題當時困擾我了很久,網上解答的很模糊,因此還是在這里記錄一下吧。

這題的難點是:如果將環形轉換為直線(直線的網上有很多解答,這里不做贅述)。

其核心思想就是:通過將數量變為 2n-1 來轉換成直線問題

當時看到這幾行字困惑了很久,一直不太理解,但之后畫圖就懂了。

 

1. 我們為了將環形變為直線,必須規定轉動順序,這里采用逆時針轉動,且以 i 作為起點,j作為終點。(右下圖)

 
         

2. 當規定好終點了,那么這環形有4種情況,我們求在這四種情況下最下的。(右上圖)

 
         

3. 關於轉換成直線,比如存在 a(0) -> b(1) -> c(2) -> d(3) 與 d(3) -> a(4) -> b(5) -> c(6)。

 
         

  第一條是 i=0,j=3的數組,第二條是 i=3,j=6 的數組。 這樣,我們就不用返回去計算了( 3->0->1->2 ???)。

 
         

4. 四種情況分別是數組中的四行,每行最后一個代表遍歷的結果,我們最后只需要遍歷這四個值,找到最小值即可。


源代碼:

 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <algorithm>
 4 #define INF 0x3f3f3f3f
 5 using namespace std;
 6 int Arr[300],Sum[300];
 7 int Min[300][300], Max[300][300];
 8 int main() {
 9     int n;
10     cin >> n;
11 
12     // 初始化數組
13     for (int i = 1; i <= n; i++) {
14         cin >> Arr[i];
15         Arr[i + n] = Arr[i];
16     }
17 
18     // 計算最大和
19     for (int i = 1; i <= 2 * n; i++) {
20         Sum[i] = Sum[i - 1] + Arr[i];
21     }
22 
23     // 開始遞歸循環
24     for (int i = 2 * n-1; i >= 1; i--) {
25         for (int j = i + 1; j < i + n; j++) {
26             Min[i][j] = INF;
27             for (int k = i; k < j; k++) {
28                 Min[i][j] = min(Min[i][j], Min[i][k] + Min[k + 1][j] + Sum[j] - Sum[i - 1]);
29                 Max[i][j] = max(Max[i][j], Max[i][k] + Max[k + 1][j] + Sum[j] - Sum[i - 1]);
30             }
31         }
32     }
33 
34     // 遍歷找到最大與最小值
35     int MaxValue = 0, MinValue = INF;
36     for (int i = 1; i <= n; i++) {
37         MaxValue = max(MaxValue, Max[i][i + n - 1]);
38         MinValue = min(MinValue, Min[i][i + n - 1]);
39     }
40 
41     cout << MinValue << endl << MaxValue << endl;
42 
43 }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM