题目描述
原题来自:NOIP 2006
在 Mars 星球上,每个 Mars 人都随身佩带着一串能量项链。在项链上有
N
N
N 颗能量珠。能量珠是一颗有头标记和尾标记的珠子,这些标记对应着某个正整数。并且,对于相邻的两颗珠子,前一颗珠子的尾标记必定等于后一颗珠子的头标记。因为只有这样,通过吸盘——Mars 人吸收能量的器官的作用,这两颗珠子才能聚合成一颗珠子,同时释放出可被吸盘吸收的能量。如果一颗能量珠头标记为
m
m
m,尾标记为
r
r
r,后一颗能量珠头标记为
r
r
r,尾标记为
n
n
n,则聚合后释放出
m
×
r
×
n
m \times r \times n
m×r×n Mars单位的能量,新珠子头标记为
m
m
m,尾标记为
n
n
n。
当需要时,Mars 人就用吸盘夹住相邻的两颗珠子,通过聚合得到能量,直到项链上只剩下一颗珠子为止。显然,不同的聚合顺序得到的总能量是不一样的。请设计一个聚合顺序使得一串珠子聚合后释放出的总能量最大。
现在给你一串项链,项链上有
n
n
n 颗珠子,相邻两颗珠子可以合并成一个,合并同时会放出一定的能量,不同珠子合并放出能量不相同,请问按怎样的次序合并才能使得释放的能量最多?
输入格式
第一行一个正整数
n
(
n
≤
100
)
n(n \leq 100)
n(n≤100)。
第二行
n
n
n 个不超过
1000
1000
1000 的正整数,第
i
(
1
≤
1
≤
n
)
i(1 \leq 1 \leq n)
i(1≤1≤n) 个数为第
i
i
i 颗珠子的头标记。
注意这是一个环。至于珠子的顺序,你可以这样确定:将项链放在桌面上,不要出现交叉,随机指定一颗珠子为第一颗珠子,按顺时针确定其它珠子的顺序。
输出格式
输出只有一行,一个不超过 2.1 × 1 0 9 2.1\times10^9 2.1×109 的正整数,表示最优聚合顺序所释放的能量。
样例
输入
4
2 3 5 10
输出
710
分析
易知这是一道区间DP。令
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]为合并
i
i
i 和
j
j
j之间的项链所能释放的最大能量,即最后
i
i
i 到
j
j
j 之间只能剩下一条项链。由区间DP的思想可知
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j] 一定是由
d
p
[
i
]
[
k
]
dp[i][k]
dp[i][k] 与
d
p
[
k
+
1
]
[
j
]
dp[k + 1][j]
dp[k+1][j]合并而来的。
(
i
≤
k
<
j
)
(i \leq k \lt j)
(i≤k<j)
于是
d
p
[
l
]
[
r
]
=
m
a
x
(
d
p
[
l
]
[
r
]
,
d
p
[
l
]
[
k
]
+
d
p
[
k
+
1
]
[
r
]
+
a
[
l
]
.
X
∗
a
[
r
]
.
Y
∗
a
[
k
]
.
Y
)
;
dp[l][r] = max(dp[l][r], dp[l][k] + dp[k + 1][r] + a[l].X * a[r].Y * a[k].Y);
dp[l][r]=max(dp[l][r],dp[l][k]+dp[k+1][r]+a[l].X∗a[r].Y∗a[k].Y);
又因为此题为一个环,我们不知道序列的头和尾在哪,这种时候一般可以把环转化为长度为
2
n
2n
2n 的 链。
代码
#include <cstdio>
#include <algorithm>
#include <climits>
#include <cmath>
#include <cstring>
using namespace std;
const int MAXN = 205;
int n, dp[MAXN][MAXN];
struct Node {
int X, Y;
} a[MAXN];
int main() {
int r, maxx = 0;
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i].X);
}
for (int i = 1; i <= n; i++) {
if (i != n)
a[i].Y = a[i + 1].X;
else {
a[i].Y = a[1].X;
}
a[i + n].X = a[i].X;
a[i + n].Y = a[i].Y;
}
for (int len = 2; len <= n; len++) {
for (int l = 1; l <= (2 * n - len + 1); l++) {
r = l + len - 1;
for (int k = l; k < r; k++) {
dp[l][r] = max(dp[l][r], dp[l][k] + dp[k + 1][r] + a[l].X * a[r].Y * a[k].Y);
}
}
}
for (int i = 1; i <= n; i++) {
maxx = max(maxx, dp[i][i + n - 1]);
}
printf("%d", maxx);
return 0;
}