本来算法使用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分
39 人评分
C语言网提供由在职研发工程师或ACM蓝桥杯竞赛优秀选手录制的视频教程,并配有习题和答疑,点击了解:
一点编程也不会写的:零基础C语言学练课程
解决困扰你多年的C语言疑难杂症特性的C语言进阶课程
从零到写出一个爬虫的Python编程课程
只会语法写不出代码?手把手带你写100个编程真题的编程百练课程
信息学奥赛或C++选手的 必学C++课程
蓝桥杯ACM、信息学奥赛的必学课程:算法竞赛课入门课程
手把手讲解近五年真题的蓝桥杯辅导课程
发表评论 取消回复