当前位置: 首页 > news >正文

20251014 区间DP总结

引子

有一些题目会要你求一些关于区间的问题,就比如什么最多什么最少之类的。由一个长区间可以由多个小区间组成这种特征的区间问题,一般可以用区间DP来解。

区间DP

区间DP一般的做法就是合并两个小区间或一次增加一个上去,常见的题目就是合并石子堆求最小体力,修改字符串成回文串求最小花费等。

区间DP的DP数组一般是二维的,两个维度分别是左端点和右端点,那么dp[i][j]dp[i][j]dp[i][j]就等于区间[i,j][i,j][i,j]的最大(小)花费什么的,答案显而易见就是dp[1][n]dp[1][n]dp[1][n]

那么什么时候需要增维呢?当我们发现推着推着条件不够的时候,就需要增维,提高一个维度,这个维度就可以恰到好处的去补充条件。

第一类区间DP模板(合并小区间)

for(int len=2;len<=n;len++){for(int l=1;l<=n-len+1;l++){int r=l+len-1;for(int k=l;k<r;k++){dp[l][r]=max(,);}}
}

第二类区间DP模板(一次加一个)

for(int len=2;len<=n;len++){for(int l=1;l<=n-len+1;l++){int r=l+len-1;dp[l][r]=max(,);}
}

例题 石子合并(弱化版)

区间DP的模板题。dp[i][j]dp[i][j]dp[i][j]在这题显然表示第iii堆石子到第jjj堆石子合并后的最小代价,并且属于合并小区间类的做法。

首先初始状态dp[i][i]=0(1≤i≤n)dp[i][i]=0(1\leq i\leq n)dp[i][i]=0(1in),其余无穷大;然后,从小到大枚举区间,枚举中断点kkk,动态转移方程为dp[l][r]=min(dp[l][r],dp[l][k]+dp[k+1][r]+s[r]−s[l−1])dp[l][r]=min(dp[l][r],dp[l][k]+dp[k+1][r]+s[r]-s[l-1])dp[l][r]=min(dp[l][r],dp[l][k]+dp[k+1][r]+s[r]s[l1]);最后答案为dp[1][n]dp[1][n]dp[1][n]

memset(dp,0x3f,sizeof(dp));
for(int i=1;i<=n;i++){dp[i][i]=0;
}
for(int len=2;len<=n;len++){//区间长度for(int l=1;l<=n-len+1;l++){//左端点int r=l+len-1;//右端点for(int k=l;k<r;k++){dp[l][r]=min(dp[l][r],dp[l][k]+dp[k+1][r]+s[r]-s[l-1]);}}
}
cout<<dp[1][n];

例题 石子合并

跟上一题没啥区别,就多了个环而已,破环成链就行了。比如一个环1,2,3,4,破环成链就是1,2,3,4,1,2,3。

剩余也就多求了个最大值。

例题 调整队形

显然是第二种区间DP,其次,我们会发现前三种操作其实可以结合到一起去,因为队伍里剔掉一个人就是在另一边加上一个人,没有区别。那么结合之后就是剔掉一个人,没了。

首先,初始值全为0;然后dp[i][j]dp[i][j]dp[i][j]表示第iii个同学到第jjj个同学最少的调整次数;接着枚举每一个区间后有了几种情况:1.a[i]==a[j]a[i]==a[j]a[i]==a[j],那么什么也不用干,直接等于dp[i+1][j−1]dp[i+1][j-1]dp[i+1][j1] 2.a[i]!=a[j]a[i]!=a[j]a[i]!=a[j],没办法,只能操作一次了,要么选择剔掉一个左边的,要么剔掉一个右边的,要么考虑把两端的人换成同样颜色的衣服,那么动态转移方程dp[i][j]=min(dp[i+1][j],min(dp[i][j−1],dp[i+1][j−1]))+1dp[i][j]=min(dp[i+1][j],min(dp[i][j-1],dp[i+1][j-1]))+1dp[i][j]=min(dp[i+1][j],min(dp[i][j1],dp[i+1][j1]))+1

for(int len=2;len<=n;len++){for(int i=1;i<=n-len+1;i++){int j=i+len-1;if(a[i]==a[j]){dp[i][j]=dp[i+1][j-1];}else{dp[i][j]=min(dp[i+1][j],min(dp[i][j-1],dp[i+1][j-1]))+1;}}
}
cout<<dp[1][n];

例题 关路灯

依然是区间DP,但是一段区间,他可能是从左端点走到右端点,也有可能恰恰相反,怎么办呢?这时就需要增维了,第三个维度表示是否从左边走到右边。

这就好办了,dp[i][j][0]dp[i][j][0]dp[i][j][0] 的推导有两种可能情况:从折返状态关闭 i,ji,ji,j 的灯(即从 i+1i+1i+1 返回),或者继续关闭第 iii 盏灯进而扩展到 (i,j)(i,j)(i,j) 状态。

dp[i][j][0]dp[i][j][0]dp[i][j][0] 的推导有两种可能情况:从折返状态关闭 i,ji,ji,j 的灯(即从 i+1i+1i+1 返回),或者继续关闭第 iii 盏灯进而扩展到 (i,j)(i,j)(i,j) 状态。

于是动态转移方程及初始值及答案:

for(int i=1;i<=n;i++){//s是前缀和数组dp[i][i][0]=dp[i][i][1]=abs(d[i]-d[c])*(s[n]-w[c]);
}
dp[c][c][0]=dp[c][c][1]=0;//从c点出发,自然不用任何代价
for(int len=2;len<=n;len++){for(int i=1;i<=n-len+1;i++){int j=i+len-1;dp[i][j][0]=min(dp[i+1][j][0]+(d[i+1]-d[i])*(s[i]+s[n]-s[j]),dp[i+1][j][1]+(d[j]-d[i])*(s[i]+s[n]-s[j]));//这样走能节省时间吗?dp[i][j][1]=min(dp[i][j-1][0]+(d[j]-d[i])*(s[i-1]+s[n]-s[j-1]),dp[i][j-1][1]+(d[j]-d[j-1])*(s[i-1]+s[n]-s[j-1]));//是否从j点折返关闭i灯会更高效?(当前状态:[i+1,j]区间关闭,i灯亮着,需从j端点返回关闭i灯)}
}
cout<<min(dp[1][n][0],dp[1][n][1]);//可以从左端点走到右端点,或从右端点走到左端点
http://www.dtcms.com/a/484029.html

相关文章:

  • 商城系统网站模板免费下载浙江平台网站建设公司
  • html5:拖放 / demo / 拖放事件(Drag Events)/ DataTransfer 对象方法
  • 早期小软件与现代大软件的区别与发展问题
  • 图解网络(第二集)
  • 做外贸服装的网站微信如何引流推广精准加人
  • 多态:C++面向对象编程的“灵魂”所在
  • 大连网站快速排名提升深圳互联网公司网站
  • 建设银行广西分行网站做自媒体的网站有哪些
  • 楼市南京做凶宅的网站郑州营销网站建设公司
  • 搭建网站需要备案吗上海网站工作室
  • 学校网站建设计入哪个会计科目类似于wordpress的网站
  • 网站seo其应用买的网站模板怎么做
  • 【GESP】C++五级考试大纲知识点梳理, (3-4) 链表-双向循环链表
  • wordpress打开网站前广告怎样免费建设个人网站
  • 网站logo更换旅游做攻略用什么网站好
  • 天津黑曼巴网站建设无锡网站排名公司
  • 【鸿蒙5.0】Scroll左右滑动
  • 抢购网站源码dz门户 WordPress
  • 百度官方网站网址wordpress微博登陆
  • 团购网站 设计方案那些网站可以做行测题
  • Spring Boot中Spring Data JPA的常用注解
  • 02117 信息组织【第四章】
  • 做带会员后台的网站用什么软件建设工程信息网一体化平台
  • 做刷单网站违法吗win7 asp.net网站架设
  • DyCoke论文阅读
  • 做翻译网站 知乎丹阳网站建设方案
  • 门户网站建设基础术语制作旅游网站的步骤
  • 开发网站建设设计公司中天建设集团网站
  • C++系列之刷题系列---栈的应用
  • 做网站着用什么软件赣榆县建设局网站