NC20252 压缩(区间dp)

一道区间dp题

我们发现由于有了M的限制,所以合并区间的时候并不能直接合并,因为不是从区间左端点开始的

因此考虑三维状态设计

f[i][j][0/1]表示i-j中是否存在M

对于不存在的情况,他有两种更新方式,一种是直接合并,一种是当偶数时,可以折半合并

对于存在的情况,这个M相当于把一个大区间的合并变成了两个小区间,因为M之后的这一段的开头相当于M之后的第一个字母。因此我们枚举M的位置进行更新

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
const int inf=0x3f3f3f3f;
int f[110][100][2];
string s;
bool check(int l,int r){
    int mid=(l+r)>>1;
    for(int i=l;i<=mid;++i){
        if(s[i]!=s[mid+i-l+1])
            return false;
    }
    return true;
}
int main(){
    ios::sync_with_stdio(false);
    int i,j,k;
    cin>>s;
    int n=s.size();
    s=" "+s;
    for(int len=1;len<=n;len++){
        for(i=1;i+len-1<=n;i++){
            j=i+len-1;
            f[i][j][0]=len;
            f[i][j][1]=inf;
            for(k=i;k<=j;k++){
                f[i][j][0]=min(f[i][j][0],f[i][k][0]+j-k);
                f[i][j][1]=min(f[i][j][1],min(f[i][k][1],f[i][k][0])+min(f[k+1][j][1],f[k+1][j][0])+1);
            }
            if(len%2==0&&check(i,j)){
                f[i][j][0]=min(f[i][j][0],f[i][(i+j)/2][0]+1);
            }
        }
    }
    cout<<min(f[1][n][0],f[1][n][1])<<endl;
    return 0;
}
View Code

 

posted @ 2021-02-20 15:51  朝暮不思  阅读(44)  评论(0编辑  收藏  举报