BZOJ 1068: [SCOI2007]压缩

Sol

区间DP.这个区间DP需要三维, \(f[i][j][k]\) 表示\([i,j]\) 这个区间中是否存在 \(M\) .

转移有两种,一种是这个区间存在 \(M\) ,那么直接枚举 \(M\) 的位置就可以了;另一种是没有 \(M\) ,那么从中间劈来,如果两边一样,显然是左边没有 \(M\) 的答案+1就可以了,还有种情况就是 左边压缩右边不压缩就行了.

随便加个记忆化搜索就行了,出口就是 \(L==R\) 如果 \(k==0\) 显然答案为1; \(k==1\) 不存在,赋个大数就可以了.

PS:这题一开始写了个70分的...不是前七十...中间有WrongAnswer的.

Code

/**************************************************************
    Problem: 1068
    User: BeiYu
    Language: C++
    Result: Accepted
    Time:20 ms
    Memory:1312 kb
****************************************************************/
 
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
 
#define debug(a) cout<<#a<<"="<<a;
const int N = 55;
const int INF = 55;
 
char c[N];
int f[N][N][2];
 
int pd(int l,int r){
    int mid=(l+r)>>1;
    for(int i=l,j=mid+1;j<=r;i++,j++) if(c[i]!=c[j]) return 0;
    return 1;
}
int DP(int L,int R,int k){
    int &res=f[L][R][k];if(~res) return res;
    if(L>R) return res=0;if(L==R){ if(k) return res=INF;else return res=1; }
    int lenth=R-L+1;res=lenth;
    if(k){
        for(int i=L;i<R;i++){
            res=min(res,DP(L,i,0)+DP(i+1,R,0)+1);
            res=min(res,DP(L,i,0)+DP(i+1,R,1)+1);
            res=min(res,DP(L,i,1)+DP(i+1,R,0)+1);
            res=min(res,DP(L,i,1)+DP(i+1,R,1)+1);
        }return res;
    }if((lenth&1)==0&&pd(L,R)) res=min(res,DP(L,L+(lenth>>1)-1,0)+1);
    for(int i=L;i<R;i++) res=min(res,DP(L,i,0)+R-i);
    return res;
}
int main(){
    scanf("%s",c+1);int n=strlen(c+1);
    memset(f,-1,sizeof(f));cout<<min(DP(1,n,0),DP(1,n,1))<<endl;
    return 0;
}

  

posted @ 2016-08-18 13:59  北北北北屿  阅读(177)  评论(0编辑  收藏  举报