[Dynamic Programming] stones merger

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

Stone merger

Time Limit: 1000 ms Memory Limit: 65536 KiB
 

Problem Description

A circle around the playground placed stones piled n. Stone is to have the order to merge into a pile. Provisions can only choose two adjacent pile into a new pile of stones, a pile of stones and a few new record for the combined score. Try to design an algorithm to calculate the n combined into a pile of stones piled minimum score and maximum score.
For a given n gravel pile, merge into a pile calculating the minimum and maximum score score.

Input

First data input line is a positive integer n, 1≤n≤100, n represents stones piled there. The second row has a number of n, respectively, represent the number of each pile of stones.

Output

There are two lines of output data, the number of line 1 is the minimum score, the second number of rows is the maximum score.

Sample Input

4
4 4 5 9

Sample Output

43
54

Algorithm finished the exam (the title a bit simple luck AK ..), but the problem was bothering me for a long time, the online answer is very vague, so it is here to record it. 

This question difficulty is: if the ring into a linear (straight-line there are many answers, not elaborated here).

The core idea is this: by the number of 2n-1 to become converted into a linear problem .

Was puzzled to see these lines for a long time, has been very understanding, but after drawing I understand.

 

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 }

Guess you like

Origin www.cnblogs.com/onetrainee/p/11955567.html