动态规划思路:
阶段i:石子的每一次合并过程,先两两合并,再三三合并,...最后N堆合并
状态s:每一阶段中各个不同合并方法的石子合并总得分。
决策:把当前阶段的合并方法细分成前一阶段已计算出的方法,选择其中的最优方案
具体来说我们应该定义一个数组s[i,j]用来表示合并方法,i表示从编号为i的石头开始合并,j表示从i开始数j堆进行合并,s[i,j]为合并的最优得分。
对于上面的例子来说,初始阶段就是s[1,1],s[2,1],s[3,1],s[4,1],s[5,1],s[6,1],因为一开始还没有合并,所以这些值应该全部为0。
第二阶段:两两合并过程如下,其中sum(i,j)表示从i开始数j个数的和
s[1,2]=s[1,1]+s[2,1]+sum(1,2)
s[2,2]=s[2,1]+s[3,1]+sum(2,2)
s[3,2]=s[3,1]+s[4,1]+sum(3,2)
s[4,2]=s[4,1]+s[5,1]+sum(4,2)
s[5,2]=s[5,1]+s[6,1]+sum(5,2)
s[6,2]=s[6,1]+s[1,1]+sum(6,2)
第三阶段:三三合并可以拆成两两合并,拆分方法有两种,前两个为一组或后两个为一组
s[1,3]=s[1,2]+s[3,1]+sum(1,3)或s[1,3]=s[1,1]+s[2,2]+sum(1,3),取其最优
s[2,3]=s[2,2]+s[4,1]+sum(2,3)或s[1,3]=s[2,1]+s[3,2]+sum(2,3),取其最优
.
.
.
第四阶段:四四合并的拆分方法用三种,同理求出三种分法的得分,取其最优即可。以后第五阶段、第六阶段依次类推,最后在第六阶段中找出最优答案即可。

Code
1
#include <stdio.h>
2
#include <string.h>
3
#define clr(a) memset(a,0,sizeof(a))
4
5
int n, amount[20], m[20][20][2];
6
7
void solve();
8
void max_min(int i, int j, int &max, int &min);
9
10
int main()
11

{
12
int i;
13
14
scanf("%d", &n);
15
for(i=1; i<=n; i++)
16
scanf("%d", &amount[i]);
17
clr(m);
18
solve();
19
printf("%d\n%d\n\n", m[1][n][1], m[1][n][0]);
20
21
return 0;
22
}
23
24
void solve()
25

{
26
int i, j, max, min;
27
28
for(i=1; i<=n; i++)
{
29
if((1+i)>n)
30
j = (1+i)%n;
31
else
32
j = 1+i;
33
m[i][2][0] = amount[i] + amount[j];
34
m[i][2][1] = amount[i] + amount[j];
35
}
36
for(i=3; i<=n; i++)
37
for(j=1; j<=n; j++)
{
38
max_min(i, j, max, min);
39
m[j][i][0] = max;
40
m[j][i][1] = min;
41
}
42
}
43
44
void max_min(int i, int j, int &max, int &min)
45

{
46
int sum=0, p=0, q, t;
47
48
while(p<i)
{
49
if((p+j)<=n)
50
q = p+j;
51
else
52
q = (p+j)%n;
53
p++;
54
sum += amount[q];
55
}
56
if((j+1)>n)
57
q = (j+1)%n;
58
else
59
q = j+1;
60
max = m[j][1][0] + m[q][i-1][0];
61
min = m[j][1][1] + m[q][i-1][1];
62
for(p=2; p<=(i-1); p++)
{
63
if((p+j)>n)
64
q = (p+j)%n;
65
else
66
q = p+j;
67
t = m[j][p][0] + m[q][i-p][0];
68
if(t > max)
69
max = t;
70
t = m[j][p][1] + m[q][i-p][1];
71
if(t < min)
72
min = t;
73
}
74
max += sum;
75
min += sum;
76
}