经典的区间型动态规划。
——————————————————————————————————
题干:https://www.luogu.org/problem/P1880
题目描述:
在一个圆形操场的四周摆放N堆石子,现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分。
试设计出1个算法,计算出将N堆石子合并成1堆的最小得分和最大得分.
输入格式:
数据的第1行试正整数N,1≤N≤100,表示有N堆石子.第2行有N个数,分别表示每堆石子的个数.
输出格式:
输出共2行,第1行为最小得分,第2行为最大得分.
样例:
输入:
4
4 5 9 4
输出:
43
54
——————————————————————————————————
思路:
1.预处理前缀和:
先进行预处理,因为之后要用到i—j的石子和,所以先统计前缀和,a[j]-a[i-1]即为i—j的石子和,因为环状结构,所以处理到2*n;
2.最优子结构:
既然要得到最优解(以最大值为例),必须每个区间合并都是最优解,假设有
一个区间不是最大得分,那这个区间更改为最大得分,最终结果一定比原结果
更优,满足最优子结构。
3.状态:
既然是线性,那我们不妨定义dp[i][j]为从i合并到j的最大得分(最小得分)。
4.状态转移方程:
那我们如何得出状态转移方程: 可以枚举一个断点k,把一段长区间化为短区间,状态转移方程很明显:
dp[i][j]=max(dp[i][k]+dp[k+1][j]+a[j]-a[i-1]).
5.转移顺序:
这道题的状态转移方程很好想,但转移顺序确实一个难点,假设正着循环,枚举k来换分i,j,那么如果通过枚举i和j进行状态转移,很显然某些k值时并不能保证已经确定过所需状态,例如:
i : 1 to 10 ; j: 1 to 10 ; k : 1 to 9 ;
当i=1,j=5,k=3时,显然状态f[k+1][j]没有结果.
所以我们需要枚举区间长度,左右端点,保证先把长度为2的合并,
再合并3 to n,这样就可保证已经确定过所需状态。
6.环形结构如何处理:因为是环形结构 ,所以我们 在后面复制一遍前面的数,把石子数扩展到2 * n;
例: 我们以样例为例子:
4 5 9 4 —> 4 5 9 4 4 5 9 4
此时便包含了所有情况
(4 5 9 4)4 5 9 4
4(5 9 4 4)5 9 4
4 5 (9 4 4 5)9 4
4 5 9 (4 4 5 9)4
正确性显然;
7.结果: 最后只需统计长度为n区间内的最优解即可。
——————————————————————————————————
代码:
#include
#include
#include
#include
#include
using namespace std;
const int MAXN = 300 + 10;
int n,ansmin,ansmax,dp1[MAXN][MAXN],dp2[MAXN][MAXN];//用dp1数组记录i--j的最大得分,用dp2数组记录i--j的最小得分
int a[MAXN]; //用a数组记录前缀和,用a[j]-a[i-1]得到i--j的和。
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
a[i+n]=a[i];
a[i]+=a[i-1];
}
for(int i=n+1;i<=2*n;i++)
a[i]+=a[i-1]; //环状结构 ,所以开到2*n
for(int p=1;p<n;p++) //区间长度
{
for(int i=1,j=i+p;(j<n+n) && (i<n+n);i++,j=i+p) //左右端点
{
dp2[i][j]=999999999;
for(int k=i;k<j;k++) //断点
{
dp1[i][j] = max(dp1[i][j], dp1[i][k]+dp1[k+1][j]+a[j]-a[i-1]);
dp2[i][j] = min(dp2[i][j], dp2[i][k]+dp2[k+1][j]+a[j]-a[i-1]);
//状态转移方程 dp[i][j]=max(dp[i][k]+dp[k+1][j]+a[j]-a[i-1]);
}
}
}
ansmin=1e9+7;
ansmax=0;
for(int i=1;i<=n;i++)
{
ansmax=max(ansmax,dp1[i][i+n-1]);
ansmin=min(ansmin,dp2[i][i+n-1]);
}//最后统计长度为n区间的最大得分的最大值 ,最小得分的最小值
cout<<ansmin<<"\n"<<ansmax;
return 0;
}
2019.10.26
By October