题目大意
有一串项链,项链上的每个珠子有首尾两个数字,首尾相连的两个珠子的尾数字和头数字相同。每次选择相连的一对珠子,得到第一个项链的首数字*第一个项链的尾数字(第二个项链的首数字)*第二个项链的尾数字的能量,并将两个珠子合并,首数字为原来第一个项链的首数字,尾数字为第二个项链的尾数字,直到只剩一个珠子为止。问每次得到的能量之和的最大值。
错误思路
本题可以换一个说法:输入数据中的数字组成一个环,每次选连续三个数字,结果加上三个数字乘积,再将中间数字去除。
我们发现这道题跟“合并果子”有些像。于是我们有一个贪心思路:每次选择环中最小的数字,将该数字和左右两侧的两个数字作为当前选择的三个数字,然后将该数字从环中删除。这样做的理由是这会使数值更大的数字被乘的次数更多,贡献更大。但是这种做法错在不能保证很大的数字乘足够多次。
那么我们可以想想动规,但这种选三去一的选择方式使我们无法写出递归式。
正解
以项链为单位进行区间DP(拆开二倍)即可。
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int MAX_N = 210; int HeadVal[MAX_N], F[MAX_N][MAX_N]; int main() { int n; scanf("%d", &n); for (int i = 1; i <= n; i++) { scanf("%d", &HeadVal[i]); HeadVal[i + n] = HeadVal[i]; } HeadVal[n * 2 + 1] = HeadVal[1]; for (int len = 2; len <= n; len++) for (int i = 1; i <= n * 2 - len + 1; i++) for (int lLen = 1; lLen <= len - 1; lLen++) F[i][i + len - 1] = max(F[i][i + len - 1], F[i][i + lLen - 1] + F[i + lLen][i + len - 1] + HeadVal[i] * HeadVal[i + lLen] * HeadVal[i + len]); int ans = 0; for (int i = 1; i <= n; i++) ans = max(ans, F[i][i + n - 1]); printf("%d ", ans); return 0; }