区间のdp

区间dp共有两种实现方法,一种是迭代式,另一种是记忆化搜索式。

  1. 一般迭代式的写法较为固定
    区间dp首先从小到大枚举区间长度l。
    然后枚举区间的起始点i。
    然后枚举区间的分割点d。
  2. 记忆化搜索

acwing 282 石子合并/《算法竞赛进阶指南》
使用前缀和简化计算

#include<bits/stdc++.h>
using namespace std;
#define N 310
int n;
int a[N];
int dp[N][N];//两个维度分别是首尾指针
int pre[N];
int main(){
    cin>>n;
    for( int i=1;i<=n;i++){
        cin>>a[i];
        pre[i]=pre[i-1]+a[i];
    }
    memset(dp,0x3f,sizeof(dp));
    for( int i=0;i<=n;i++){
        dp[i][i]=0;
    }
    for( int l=0;l<=n;l++){
        for( int i=1;i+l<=n;i++){
            for( int d=i+1;d<=l+i;d++){
                dp[i][i+l]=min(dp[i][i+l],dp[i][d-1]+dp[d][i+l]+pre[i+l]-pre[i-1]);
            }
        }
    }
    cout<<dp[1][n];
}

acwing 1068《信息学奥赛一本通》环形石子合并
把环形拉直成一个长度为2n的直线
这是应对环形问题常用的手段

#include<bits/stdc++.h>
using namespace std;
#define N 410
typedef long long ll;
int a[N];
int dp1[N][N];//min
int dp2[N][N];//max
int pre[N];

int main(){
    int n;
    cin>>n;
    for( int i=1  ;i<=n  ;i++) cin>>a[i];
    for( int i=n+1;i<=2*n;i++) a[i]=a[i-n];
    for( int i=1  ;i<=n*2;i++) pre[i]=pre[i-1]+a[i];
    memset(dp1,0x3f,sizeof(dp1));
    memset(dp2,0,sizeof(dp2));
    for( int i=0  ;i<=2*n;i++) {
        dp1[i][i]=0;
    }
    for( int l=1;l<=n;l++)//the lenth
        for( int i=1;i+l<=n*2;i++){ //the beginner
            for( int d=i+1;d<=i+l;d++){//the divsion
                dp1[i][i+l]=min(dp1[i][i+l] , dp1[i][d-1]+dp1[d][i+l]+pre[i+l]-pre[i-1]);
                dp2[i][i+l]=max(dp2[i][i+l] , dp2[i][d-1]+dp2[d][i+l]+pre[i+l]-pre[i-1]);
            }
        }
    // cout<<dp1[4][6]<<endl;
    int ans=0x7fffffff;
    for( int i=1;i<=n;i++){
        ans=min(ans,dp1[i][i+n-1]);
    }
    cout<<ans<<endl;
    ans=0;
    for( int i=1;i<=n;i++){
        ans=max(ans,dp2[i][i+n-1]);
    }
    cout<<ans<<endl;
    
}

acwing320 能量项链《算法竞赛进阶指南》

#include<bits/stdc++.h>
using namespace std;
typedef  long long ll;
#define N 210
ll a[N];
ll dp[N][N];
int main(){
    int n;
    cin>>n;
    for( int i=1;i<=n;i++){
        cin>>a[i];
        a[i+n]=a[i];
    }
    ll ans=0;
    a[n+n+1]=a[1];
    for( int l=1;l<=n;l++)
        for( int i=1;i+l<=n*2;i++){
            int r=i+l-1;
            for( int d=i+1;d<=r;d++){//注意控制d的范围,边界敏感
                dp[i][r]=max( dp[i][r] , dp[i][d-1]+dp[d][r]+a[i]*a[d]*a[r+1] );
            }
        }
        
    for( int i=1;i<=n;i++){
        ans=max(dp[i][i+n-1],ans);
        // cout<<i<<" "<<i+n-1<<" "<<dp[i][i+n-1]<<endl;
    }
    cout<<ans<<endl;
    
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值