区间DP

区间DP具有两种形式的模板

这里以P1775 石子合并(弱化版) - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)为例

第一种是枚举区间长度然后进行动态规划:
  枚举合并的区间然后进行递推:

复制代码
#include<bits/stdc++.h> using namespace std; const int N=2020; int n,s[N],dp[N][N]; int main() { cin>>n; for(int i=1;i<=n;i++){ int x; cin>>x; s[i]=s[i-1]+x; } for(int len=2;len<=n;len++){ for(int i=1;i+len-1<=n;i++){ int l=i,r=i+len-1; dp[l][r]=1e9; 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]; return 0; }
复制代码

第二种是枚举区间端点 lr 然后用中间点为媒介进行区间的更新,类似与图论中的Floyd算法:

这里记住左端点一定是倒序遍历,不然会遍历不全

复制代码
#include<bits/stdc++.h> #define int long long using namespace std; const int N=4040; int dp[N][N],n,a[N],s[N]; signed main(){ cin>>n; for(int i=1;i<=n;i++) cin>>a[i],s[i]=s[i-1]+a[i]; for(int i=n;i>=1;i--){ for(int j=i+1;j<=n;j++){ dp[i][j]=1e9; for(int k=i;k<j;k++) dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+s[j]-s[i-1]); } } cout<<dp[1][n]; }
复制代码

 

例:

P2858 [USACO06FEB] Treats for the Cows G/S - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

1. 设 dp[i][j] 是区间 lr 没有被卖出,于此之外的全部被卖出了,那么正常进行区间dp即可

复制代码
#include<cstdio> #include<algorithm> #include<iostream> using namespace std; int n; int v[2100]; int dp[2100][2100]; int main(){ //freopen("A.in","r",stdin); //freopen("A.out","w",stdout); scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&v[i]);//记录价值 dp[1][n]=0;//初始时什么都没卖出 所以是0 for(int i=n-1;i>=0;i--){//枚举区间长度 for(int j=1;j+i<=n;j++){//枚举左端点 int g=j+i;//右端点 dp[j][g]=max(dp[j-1][g]+v[j-1]*(n-g+j-1),dp[j][g+1]+v[g+1]*(n-g+j-1));//区间[i,j]是由区间[i-1,j]或区间[i,j+1]转移来的,切记dp[i][j]是未售出的区间。 } } for(int i=1;i<=n;i++) dp[i][i]+=n*v[i];//dp[i][i]表示除i以外的物品都售出了 最后售出i 所以加上v[i]*n int ans=0; for(int i=1;i<=n;i++) ans=max(ans,dp[i][i]);//比较出最大值 printf("%d",ans); return 0; }
复制代码

2. 设 dp[i][j] 是当前第 i 次买卖, 左边只卖了 j个,那么从右边开始卖的数量自然而然的也就得出,dp即可

复制代码
#include<bits/stdc++.h> #define int long long using namespace std; const int N=4040; int n,m,dp[N][N],a[N],res,s[N]; signed main(){ cin>>n; for(int i=1;i<=n;i++) cin>>a[i]; for(int i=1;i<=n;i++) for(int j=0;j<=i;j++) dp[i][j]=max(dp[i-1][j]+a[n-i+1+j]*i,dp[i-1][j-1]+a[j]*i); for(int i=0;i<=n;i++) res=max(res,dp[n][i]); cout<<res; }
复制代码

 


__EOF__

本文作者Sakurajimamai
本文链接https://www.cnblogs.com/o-Sakurajimamai-o/p/17992467.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   o-Sakurajimamai-o  阅读(2)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
-- --
点击右上角即可分享
微信分享提示