咖啡


私信TA

用户名:Tianxn

访问量:80779

签 名:

十年OI一场空,不开LL见祖宗。

等  级
排  名 7
经  验 19059
参赛次数 6
文章发表 192
年  龄 22
在职情况 学生
学  校 西安航空学院
专  业 软件工程

  自我简介:

本来算法使用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分

3 人评分

  评论区

深受启发,十分感谢
2021-10-16 20:07:58 | |
nice
2021-10-07 14:12:22 | |
MD问题收到,已经转告RD并且扣一个鸡蛋
2021-08-31 16:51:01 | |
  • «
  • 1
  • »