其他分享
首页 > 其他分享> > 区间DP

区间DP

作者:互联网

概念

区间类型动态规划是线性动态规划的拓展,它在分阶段划分问题时,与阶段中元素出现的顺序和由前一阶段的哪些元素合并而来有很大的关系。(例:f[i][j]=f[i][k]+f[k+1][j])

区间类动态规划的特点:

 

石子合并 [P1880]

题目描述

在一个圆形操场的四周摆放 N 堆石子,现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分。

试设计出一个算法,计算出将 N 堆石子合并成 1 堆的最小得分和最大得分。

 

思路:

首先这是一个环形结构,我们需要把它转换为线性结构来处理会比较方便,所以我们需要把线性长度增加一倍,使得首位可以相连。

for(int i=1;i<=n;i++)
scanf("%d", &a[i]),a[n+i]=a[i],s[i]=s[i-1]+a[i];

 这样我们就可以在线性结构上解决问题,这题是一道区间DP的模板题。

对应到动态规划中,就是两个长度较小的区间上的信息向一个更长的区间发生了转移,划分点k就是转移的决策,区间长度就是DP的阶段。根据动态规划“选择最小的能覆盖状态空间的维度集合”的思想,可以只用左、右端点表示DP的状态。

 

dp[i][j]表示区间从i到j的最小合并值;

dpp[i][j]表示区间从i到j的最大合并值;

s[i]表示前缀和;

通过枚举断点k来找出每个区间最优值再合并;

状态转移方程:

dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+s[j]-s[i-1]);
dpp[i][j]=max(dpp[i][j],dpp[i][k]+dpp[k+1][j]+s[j]-s[i-1]);

 

完整代码:

#include<bits/stdc++.h>
using namespace std;
int n,a[3005],s[3005],dp[3005][3005],dpp[3005][3005];

int main()
{
    scanf("%d", &n);
    for(int i=1;i<=n;i++)//断环成链 
    scanf("%d", &a[i]),a[n+i]=a[i],s[i]=s[i-1]+a[i];
    for(int i=n+1;i<=2*n;i++)//前缀和 
    s[i]=s[i-1]+a[i];
    for(int l=2;l<=n;l++)//区间长度 
    {
        for(int i=1;l+i-1<=2*n;i++)//左端点 
        {
            int j=l+i-1;//右端点 
            dp[i][j]=1e8;
            dpp[i][j]=-1e8;
            for(int k=i;k<j;k++)//断点k 
            {
                dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+s[j]-s[i-1]);
                dpp[i][j]=max(dpp[i][j],dpp[i][k]+dpp[k+1][j]+s[j]-s[i-1]);
            }
        }
    }
    int maxx=-1e8,minn=1e8;
    for(int i=1;i<=n;i++)//遍历找最大最小值 
    {
    	maxx=max(maxx,dpp[i][i+n-1]);
    	minn=min(minn,dp[i][i+n-1]);
	}
	printf("%d\n%d",minn,maxx);
    return 0;
}

 

能量项链 [P1063]

#include<bits/stdc++.h>
using namespace std;
int n,maxx,a[300],dp[300][300];
int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i],a[i+n]=a[i];
	}
	for(int i=2;i<2*n;i++)
	{
		for(int j=i-1;j>=1&&i-j<n;j--) 
		{
			for(int k=j;k<i;k++)
			{
		    //转移方程 = max(原来能量,左边能量 +右边能量 +将两区间合并的能量);
		    //两区间合并能量=左区间第一个珠子*右区间第一个珠子*总区间后面一个珠子; 
				dp[j][i]=max(dp[j][i],dp[j][k]+dp[k+1][i]+a[i+1]*a[k+1]*a[j]);
				maxx=max(dp[j][i],maxx);
			}
		}
	}
	cout<<maxx;
	return 0;
}

 

 

总结:

基本特征:将问题分解成为两两合并的形式。

解决方法:对整个问题设最优值,枚举合并点,将问题分解成为左右两个部分,再将左右两个部分的最优值进行合并得到原问题的最优值。

 

设i到j的最优值,枚举剖分(合并)点,将(i,j)分成左右两区间,分别求左右两边最优值,如下图:

 

状态转移方程的一般形式如下:

 

 

 

 

 

标签:dpp,int,合并,DP,区间,最优,dp
来源: https://www.cnblogs.com/wxk1213/p/15655070.html