区间DP总结(二)

好题

poj 1141 Brackets Sequence 括号匹配并输出方案
洛谷2858 奶牛零食 区间长度逐渐缩小
洛谷1622 释放囚犯 将问题向区间DP转化的思想
参考博客:剑锋OI博客动态规划之区间DP专题

区间DP小结

区间DP常用模板

/*  初始化dp数组及len为1的情况*/
            for(int len=2;len<=n;len++){//枚举长度
            for(int l=1;l<=n-len+1;l++){//状态,区间左端点
            int r=l+len-1;
            for(int j=l;j<r;j++){//枚举断点
												//转移方程决策
            }
        }
    }

重点是区分阶段、状态、决策,以及状态转移方程的实现。

1、【HDU4745】Two Rabbits

求最大非连续回文串

#include<iostream>
#include<cstdio>
#include<cstring>
#define N 1005
#define INF 1e9

using namespace std;
int n,dp[2*N][2*N],a[2*N];

int main()
{
    while(cin>>n&&n){
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=n;i++){
            cin>>a[i];
            a[i+n]=a[i];
            dp[i][i]=dp[i+n][i+n]=1;
        }
        for(int len=2;len<=n;len++){
            for(int l=1;l<=2*n-len+1;l++){
                int r=l+len-1;
                if(a[l]==a[r]) dp[l][r]=max(dp[l][r],dp[l+1][r-1]+2);
                dp[l][r] = max(dp[l][r], max(dp[l+1][r], dp[l][r-1]));
            }
        }
        int ans=0;
        for(int i=1;i<=n;i++){
            ans=max(ans,dp[i][i+n-1]);
            ans=max(ans,dp[i][i+n-2]+1);
        }
        cout<<ans<<endl;
    }
}

2、【POJ1141】Brackets Sequence 括号匹配

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>

using namespace std;
#define N 105
#define INF 1e9
int d[N][N];
int pos[N][N];
char s[N];  //接受初始数据
void output(int l,int r)
{
    if(l==r){
        if(s[l]=='('||s[l]==')') cout<<"()";
        else cout<<"[]";
        return ;
    }
    if(l<r){
        if(pos[l][r]==-1)
        {
            cout<<s[l];
            output(l+1,r-1);
            cout<<s[r];
        }
        else {
            output(l,pos[l][r]);
            output(pos[l][r]+1,r);
        }
    }
}
int main()
{
    cin>>s;
    int n=strlen(s)-1;
    for(int i=0;i<=n;i++){
        d[i][i]=1;
    }
    for(int len=2;len<=n+1;len++){
        for(int l=0;l<=n-len+1;l++){
            int r=l+len-1;
            d[l][r]=INF;
            if((s[l]=='('&&s[r]==')')||(s[l]=='['&&s[r]==']'))
            {
                d[l][r]=d[l+1][r-1];
                pos[l][r]=-1;
            }
            for(int j=l;j<r;j++){
                if(d[l][r]>(d[l][j]+d[j+1][r])){
                    d[l][r]=d[l][j]+d[j+1][r];
                    pos[l][r]=j;
                }
            }
        }
    }
    output(0,n);
    cout<<endl;
    return 0;
}

下面的两道题目比较难搞,不能明显的看出是区间DP,一看上去,还以为贪心。划分好阶段、状态以后,转移方程需要好好的想想。
【洛谷1622】释放囚犯

#include<bits/stdc++.h>
#define N 1001

using namespace std;
int n,m,ans,a[N],sum[101],dp[N][N];
int main()
{
    cin>>n>>m;
    for(int i=1;i<=m;i++) cin>>a[i];
    a[++m]=n+1;
    sort(a+1,a+m+1);
    for(int i=1;i<=m;i++){
        sum[i]=sum[i-1]+a[i]-a[i-1]-1;
    }

    memset(dp,0x3f,sizeof(dp));
    for(int i=1;i<=m;i++){
        dp[i][i]=0;
    }
    for(int len=2;len<=m;len++)
    {
        for(int l=1;l+len-1<=m;l++){
            int r=l+len-1;
            for(int j=l;j<=r;j++){
                dp[l][r]=min(dp[l][r],dp[l][j]+dp[j+1][r]+sum[r]-sum[l-1]+r-l-1);
            }
        }
    }
    cout<<dp[1][m];
}

4、【洛谷 P5445 APIO2019】路灯

#include<iostream>
#include<cstdio>
#include<cstring>
#define N 51
using namespace std;
int n,a[N],b[N],c,dp[N][N][2],sum[N];
int main()
{
    cin>>n>>c;
    memset(dp,0x3f,sizeof(dp));
    for(int i=1;i<=n;i++){
        cin>>a[i]>>b[i];
        sum[i]=sum[i-1]+b[i];
    }
    dp[c][c][1]=dp[c][c][0]=0;
    for(int len=2;len<=n;len++){
        for(int l=1;l+len-1<=n;l++){
            int r=l+len-1;
            for(int k=l;k<r;k++){
                dp[l][r][0]=min(dp[l+1][r][0]+(a[l+1]-a[l])*(sum[l]+sum[n]-sum[r]),dp[l+1][r][1]+(a[r]-a[l])*(sum[l]+sum[n]-sum[r]));
                dp[l][r][1]=min(dp[l][r-1][0]+(a[r]-a[l])*(sum[n]+sum[l-1]-sum[r-1]),dp[l][r-1][1]+(a[r]-a[r-1])*(sum[n]+sum[l-1]-sum[r-1]));
            }
        }
    }
    int ans=min(dp[1][n][1],dp[1][n][0]);
    cout<<ans<<endl;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值