首页 > 其他分享 >区间DP

区间DP

时间:2024-02-17 16:55:04浏览次数:22  
标签:ch int len num 区间 DP

先看一下模板

点击查看代码

//f[i][j]表示从i到j区间的值 
for(int len=2;len<=n;len++)//len表示区间长度 
{
	for(int i=1;i+len-1<=n;i++)//关系一般为2<=i<=k<j<=n
	{
		int j=i+len-1;//j的求值,开始点+区间长度-1 
		for(int k=i;k<j;k++)
		{
			f[i][j]=min/max(状态转移方程,f[i][j]);
//			一般为f[i][k] 运算符 f[k+1][j]...
//			可以理解为合并i到k和k+1到j这两个区间,同时进行操作 
		}
	}
}

接下来看看例题吧
区间合并求值问题

石子合并

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=250;
int f[N][N],g[N][N];
int a[N],s[N]; 
int main()
{
	int n;
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
		s[i]=s[i-1]+a[i];
	}
	memset(f,0x3f,sizeof(f));
	for(int i=1;i<=n;i++)
	{
		f[i][i]=0;
	}
	for(int len=2;len<=n;len++)
	{
		for(int i=1;i+len-1<=n;i++)
		{
			int j=i+len-1;
			for(int k=i;k<j;k++)
			{
				f[i][j]=min(f[i][k]+f[k+1][j]+s[j]-s[i-1],f[i][j]);
				g[i][j]=max(g[i][k]+g[k+1][j]+s[j]-s[i-1],g[i][j]);
			}
		}
	}
	cout<<f[1][n]<<endl;
	cout<<g[1][n];
} 

环状区间DP
区间DP还有一类特殊题型,把原本的线性结构拓展到环状结构。
这比较好处理,只需要把数据复制,再贴到原来的数据后面。

能量项链

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=1000;
int n;
int a[N],f[N][N];
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<=n*2+1-len;i++)
		{
			int j=i+len-1;
			for(int k=i;k<j;k++)
			{
				if(f[i][j]<f[i][k]+f[k+1][j]+a[i]*a[1+k]*a[j+1])
				{
					f[i][j]=f[i][k]+f[k+1][j]+a[i]*a[1+k]*a[j+1];
				}
			}
		}
	}
	int ans=0;
	for(int i=1;i<=n*2;i++)
	{
		ans=max(f[i][i+n-1],ans);
	} 
	cout<<ans;
} 

多边形

这道题的难点在于它同时有负数和乘号,我们无法正常的求最大值,因为负数乘负数为一个正数。
因此我们要同时维护一个最大值和一个最小值。思路就是这样,看代码吧。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=1000;
int n;
struct lmy
{
	int num;
	char ch;
}a[N];
int f[N][N],g[N][N],s[N];
int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i].ch>>a[i].num;
		a[i+n].ch=a[i].ch;
		a[i+n].num=a[i].num; 
	}
	memset(f,-0x3f,sizeof(f));
	memset(g,0x3f,sizeof(g));
	for(int i=1;i<=2*n;i++)
	{
		f[i][i]=g[i][i]=a[i].num;
	}
	for(int len=1;len<=n;len++)
	{
		for(int i=1;i<=2*n-len+1;i++)
		{
			int j=i+len-1;
			for(int k=i;k<j;k++)
			{
				if(a[k+1].ch=='t')
				{
					f[i][j]=max(f[i][k]+f[k+1][j],f[i][j]);
					g[i][j]=min(g[i][k]+g[k+1][j],g[i][j]);
				}
				if(a[k+1].ch=='x')
				{
					int h1=f[i][k]*f[k+1][j];
					int s1=g[i][k]*g[k+1][j];
					int w1=max(h1,s1);
					
					int h2=f[i][k]*g[k+1][j];
					int s2=g[i][k]*f[k+1][j];
					int w2=min(h2,s2);
					f[i][j]=max(w1,f[i][j]);
					int w3=min(g[i][j],g[i][k]*g[k+1][j]);
					g[i][j]=min(w2,w3);
				}
			}
		}
	}
	int ans=0;
	for(int i=1;i<=n*2;i++)
	{
		ans=max(ans,f[i][i+n-1]);
	}
	cout<<ans<<endl;
	for(int i=1;i<=n;i++)
	{
		if(f[i][i+n-1]==ans)
		{
			cout<<i<<" ";
		}
	}
} 

总结
区间DP可能比较难理解,但它的应用比较简单,只要记住模板,找到状态转移方程,就可以解决问题。
好了,就到这里了,拜拜。

标签:ch,int,len,num,区间,DP
From: https://www.cnblogs.com/zhengchenxi/p/18018120

相关文章

  • 坐标DP
    坐标DP相较来说会比较简单。直接上例题1.坐标遍历问题传纸条点击查看代码#include<bits/stdc++.h>usingnamespacestd;constintN=120;intm,n;intg[N][N],f[N][N][N];intans;intmain(){ cin>>n>>m; for(inti=1;i<=n;i++) { for(intj=1;j<=m;j++) { ......
  • 关于动态规划(Dynamic Programming)的若干思考 ------ [2.线性dp]
    线性dp的两个经典题目:最长上升子序列(LIS)and最长公共子序列(LCS)1.LIS核心代码#include<bits/stdc++.h>usingnamespacestd;constintmaxn=2024;intcnt=0,ans=1;intf[maxn],a[maxn],c[maxn];voidout(intx){ if(x==0)return; out(c[x]); cout<<a[x]<<......
  • 线性dp
    基本应用:最长上升子序列:题目描述设有由n个不相同的整数组成的数列,记为:b(1)、b(2)、……、b(n)且b(i)<>b(j)(i<>j),若存在i1<i2<i3<…<ie且有b(i1)<b(i2)<…<b(ie)则称为长度为e的不下降序列。程序要求,当原数列出之后,求出最长的上升序列。例如13,7,9,16,38,24,37,18,44,19,21,22,63......
  • dp总结(背包,线性,区间,坐标,树形)
    背包dp0/1背包这种背包会提供可选的物品,背包的容积以及每件物品的价值,并且在选择物品是每件物品只有选一件或不选两种状态。例题输入4512243445输出8二维解法代码//状态转移方程为:f[i][j]=max(f[i][j],f[i-1][j-v[i]]+w[i])#include"bits/stdc++.h"using......
  • 坐标dp
    坐标dp典型例题:传纸条题目描述小渊和小轩是好朋友也是同班同学,他们在一起总有谈不完的话题。一次素质拓展活动中,班上同学安排做成一个m行n列的矩阵,而小渊和小轩被安排在矩阵对角线的两端,因此,他们就无法直接交谈了。幸运的是,他们可以通过传纸条来进行交流。纸条要经由许多同学传......
  • 线性DP
    这篇主要涉及线性DP。先介绍给模型,求最长上升子序列。点击查看代码#include<bits/stdc++.h>usingnamespacestd;constintN=1020;intn;intf[N],ans,a[N];intpre[N],te;voidoutput(intx){ if(x==0) { return; } output(pre[x]); cout<<a[x]<<"";......
  • 区间dp
    区间dp区间dp属于线性dp的一种,以“区间长度”作为dp的“阶段”,用两个坐标(区间的左、右端点)描述每个维度。区间dp中,一个状态往往由若干个比它更小且包含于它的区间所代表的阶段转移而来,所以区间dp的决策往往就是划分dp的方法。典型例题:石子合并for(inti=1;i<=n;i++)f[i][i]=......
  • 五大基础dp
    动规条件•最优化原理:如果问题的最优解所包含的子问题的解也是最优的,就称该问题具有最优子结构,即满足最优化原理。•无后效性:即某阶段状态一旦确定,就不受这个状态以后决策的影响。也就是说,某状态以后的过程不会影响以前的状态,只与当前状态有关。•有重叠子问题:即子问题之......
  • 背包dp
    01背包:所谓01背包,就是每种物体有一个价值且数量只有一个,给定一个背包容量,在不超出背包容量的前提下在n个物体中取m个,求最大价值。点击查看代码//f[i]指体积为i时的最大价值for(inti=1;i<=n;i++){//第一层循环是指遍历每种物体,n是物体种数 for(intj=m;j>=v[i];j--){//第......
  • 背包DP
    下面介绍一下背包DP主要题型基础模型(没什么好说的,上模板)1.01背包最主要的模板,应用很多,很重要!!!倒着遍历容积,不会受后选小的f[i][j]影响,已经选过的物品不会再选一遍。点击查看代码#include<bits/stdc++.h>usingnamespacestd;constintN=10020;intf[N];intn,m;intv......