【算法模板】动态规划:区间DP

【算法模板】动态规划:区间DP

概念

区间DP也属于线性DP中的一种,它以“区间长度”作为DP 的“阶段”,使用两个坐标(区间的左、右端点)描述每个维度。在区间DP中, 一个状态由若干个比它更小且包含于它的区间所代表的状态转移而来,因此,区间D 的决策往往就是划分区间的方法。区间DP 的初态一般就由长度为1的“元区间”构成。这种向下划分再向上递推的模式与某些树形结构,也有很大的相似之处。

编程实现动态规划的状态转移方程时,务必分清阶段、状态与决策,三者应当按照从外到内的顺序依次循环

区间DP一般遵循以下方法:

  1. 从小到大枚举区间长度。
  2. 对于每一个区间长度,枚举该长度的每一个区间。
  3. 对于每一个区间,枚举所有可能出现的两个子区间的组合。
  4. 对于每一个子区间的组合,计算出合并所需代价。
  5. 求出当前区间的最优值。例如令f[i][j]为区间[l,r]的最大价值,则f[i][j]=max{f[i][k]+f[k+1][r]+cost|l<=k<r}.

模板

for (int x = 0; x < n; x++){//枚举长度
    for (int i = 1; i + x <= n; i++){//枚举起点
        dp[i][i] = 1;
        int j = x + i;//终点
        dp[i][j] = dp[i + 1][j] + 1;
        for (int k = i + 1; k <= j; k++) {
            if (a[i] == a[k])
                dp[i][j] = min(dp[i][j], dp[i][k ‐ 1] + dp[k +1][j]);
        }
    }
}

例题

石子合并

石子合并 - AcWing题库

#include <bits/stdc++.h>
using namespace std;
const int INF=0x3f3f3f3f;
int main(){
    int n;cin>>n;
    vector<int> arr(n+1);
    vector<vector<int>> dp(n+1,vector<int>(n+1,INF));
    for(int i=1;i<=n;i++)cin>>arr[i];
    for(int i=1;i<=n;i++)arr[i]+=arr[i-1];
    for(int i=1;i<=n;i++)dp[i][i]=0;

    for(int len=2;len<=n;len++){
        for(int l=1;l+len-1<=n;l++){
            int r=l+len-1;
            for(int mid=l;mid<r;mid++){
                dp[l][r]=min(dp[l][r],dp[l][mid]+dp[mid+1][r]+arr[r]-arr[l-1]);
            }
        }
    }
    cout<<dp[1][n]<<endl;
}

涂色

涂色 - 蓝桥云课 (lanqiao.cn)

#include <bits/stdc++.h>
using namespace std;
const int INF=0x3f3f3f3f;
int main(){
    string S;cin>>S;
    const int N=S.size();
    vector<vector<int>> dp(N,vector<int>(N,INF));
    for(int i=0;i<N;i++)dp[i][i]=1;

    for(int len=2;len<=N;len++){
        for(int l=0;l+len-1<N;l++){
            int r=l+len-1;
            if(S[l]==S[r]){
                dp[l][r]=min(dp[l+1][r],dp[l][r-1]);
            }
            else for(int k=l;k<r;k++){
                dp[l][r]=min(dp[l][r],dp[l][k]+dp[k+1][r]);
            }
        }
    }
    cout<<dp[0][N-1]<<endl;
}

制作回文串

制作回文串 - 蓝桥云课 (lanqiao.cn)

#include <bits/stdc++.h>
using namespace std;
const int INF=0x3f3f3f3f;
int main(){
    int n,m;cin>>n>>m;
    string s;cin>>s;
    int cost[26]={0};
    while(n--){
        char c;cin>>c;
        int x,y;cin>>x>>y;
        cost[c-'a']=min(x,y);
    }
    vector<vector<int>> dp(m,vector<int>(m,INF));
    for(int i=0;i<m;i++)dp[i][i]=0;
    for(int len=2;len<=m;len++){
        for(int l=0;l+len-1<m;l++){
            int r=l+len-1;
            if(s[l]==s[r]){
                if(len==2)dp[l][r]=0;
                else dp[l][r]=dp[l+1][r-1];
            }
            else dp[l][r]=min(dp[l][r-1]+cost[s[r]-'a'],dp[l+1][r]+cost[s[l]-'a']);
        }
    }
    cout<<dp[0][m-1]<<endl;
}

能量项链

能量项链 - 蓝桥云课 (lanqiao.cn)

#include <bits/stdc++.h>
int main(){
    int n;std::cin>>n;
    std::vector<int> arr(n*2+1);
    for(int i=0;i<n;i++)std::cin>>arr[i],arr[n+i]=arr[i];
    arr[n*2]=arr.front();
    std::vector<std::vector<int>> dp(n*2,std::vector<int>(n*2));
    for(int len=2;len<=n;len++){
        for(int l=0;l+len-1<n*2;l++){
            int r=l+len-1;
            for(int k=l;k<r;k++){
                dp[l][r]=std::max(dp[l][r],dp[l][k]+dp[k+1][r]+arr[l]*arr[k+1]*arr[r+1]);
            }
        }
    }
    int ans=0;
    for(int l=0;l<=n;l++)ans=std::max(ans,dp[l][l+n-1]);
    std::cout<<ans<<std::endl;
}
  • 14
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值