本来算法使用MarkDown写,但是发现我们的MarkDown真的难用~
题目大意:
有n个珠子编号为1~n且首尾相接为环状,每一个珠子有头标记和尾标记,第i个珠子的尾标记是第i-1个珠子的头标记,第i个珠子的尾标记是第i+1个珠子的头标记;特别的,第n珠子的尾标记是第1个珠子的头标记。
解题思路:
假设有4个珠子,我们只看最后一次合并,一共有以下4种合并方式:
第一种:①+ ②③④
第二种:①②+ ③④
第三种:①②③+ ④
第四种:④①+ ②③
注意,我们只看最后一次合并,那么对于第一种中的②③④使用同样的方式可以分为②+③④、②③+④,其他的情况也类似。
这种思想其实就是区间DP的思路了。
但是这个题目是首尾相接呈环状的,怎么处理环状呢?对于这类环状问题,处理的方式就是:断环为链。简单来说就是,这个序列是1~n,在复制一个同样的放到n后面,那么序列就成1~2n了。
区间DP模板代码:
枚举区间长度len(2 ~ n) 枚举区间起点i(1 ~ i+len-1<=2n) 算出区间终点j = i+len-1 枚举区间断点k(i <= k < j) 状态转移 注意事项:
ok,对于动态规划题目一定搞清楚三点:状态表示,初始状态,状态转移。(建议自己写动归的题目的时候先把这三点列出来再去写)
状态表示:dp[i][j]表示第i颗珠子到第j颗珠子聚合成一颗珠子后所释放的最大能量
初始状态:dp[i][i]=0,单独一个珠子无法释放能量
状态转移:dp[i][j] = max{dp[i][k] + dp[k+1][j] + a[i]*a[k+1]*a[j+1]},i≤k<j,k为断点
注意:从第k个位置断开(i~k已经聚合成一个珠子且k+1~j也聚合成一个珠子,这个在状态转移的过程已经处理好了)左右两个珠子聚合得到的能量为:a[i]*a[k+1]*a[j+1]。
参考代码:
#include <iostream> using namespace std; int n, a[405], dp[405][405], ans; int main() { cin >> n; for (int i = 1; i <= n; ++i) { cin >> a[i]; a[i+n] = a[i]; } for (int len = 2; len <= n; ++len) for (int i = 1; i + len - 1 <= 2*n; ++i) { int j = i + len - 1; for (int k = i; k < j; ++k) dp[i][j] = max(dp[i][j], dp[i][k] + dp[k+1][j] + a[i] * a[k+1] * a[j+1]); } for (int i = 1; i <= n; ++i) ans = max(ans, dp[i][i+n-1]); cout << ans << endl; return 0; }
0.0分
43 人评分
题主的代码似乎有些细节错误,从15和17行可以看出,j最大可以取2*n,但是19行出现了j+1,导致数据溢出,解决办法是可以将a数组里的数据由2*n扩展到3*n,但是题主的代码提交无任何问题,可能是测试数据不够全面导致
1234珠子的最后一次合并不应该有6种吗,123+4,234+1,341+2,412+3,12+34,23+14?
蓝桥杯历届试题-九宫重排 (C++代码)浏览:2812 |
【蟠桃记】 (C语言代码)浏览:708 |
不容易系列2 (C语言代码)浏览:640 |
WU-蓝桥杯算法提高VIP-Quadratic Equation (C++代码)浏览:1808 |
用筛法求之N内的素数。 (C语言代码)浏览:685 |
C语言程序设计教程(第三版)课后习题3.7 (C语言代码)浏览:268 |
C语言程序设计教程(第三版)课后习题9.3 (C语言代码)浏览:750 |
C语言程序设计教程(第三版)课后习题5.6 (C语言代码)浏览:594 |
用筛法求之N内的素数。 (C语言代码)浏览:595 |
Tom数 (C语言代码)浏览:598 |
咖啡 2022-03-25 10:06:57 |
你好,这个对答案并没有影响,因为是在复制数组之后的基础上考虑,出现2*n+1的这个情况其实已经在前面计算过了(这里数组不会出现溢出),这里最后一次计算也是重复计算,当然可以直接写成 < 2*n 也没有任何问题。感谢您提出问题。