咖啡


私信TA

用户名:Tianxn

访问量:138086

签 名:

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

等  级
排  名 10
经  验 27291
参赛次数 10
文章发表 197
年  龄 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分

43 人评分

  评论区

题主的代码似乎有些细节错误,从15和17行可以看出,j最大可以取2*n,但是19行出现了j+1,导致数据溢出,解决办法是可以将a数组里的数据由2*n扩展到3*n,但是题主的代码提交无任何问题,可能是测试数据不够全面导致
2022-03-18 00:11:41
1234珠子的最后一次合并不应该有6种吗,123+4,234+1,341+2,412+3,12+34,23+14?
2022-03-17 13:17:25
收获良多
2022-03-08 17:25:10
漂亮啊!
2022-03-06 17:39:17
深受启发,十分感谢
2021-10-16 20:07:58
nice
2021-10-07 14:12:22
MD问题收到,已经转告RD并且扣一个鸡蛋
2021-08-31 16:51:01
  • «
  • 1
  • »