区间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;
}

第二种是枚举区间端点 $l$ 和 $r$ 然后用中间点为媒介进行区间的更新,类似与图论中的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]$ 是区间 $l-r$ 没有被卖出,于此之外的全部被卖出了,那么正常进行区间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;
}

 

posted @ 2024-01-28 07:35  o-Sakurajimamai-o  阅读(17)  评论(0)    收藏  举报
-- --