bzoj1068: [SCOI2007]压缩

区间dp。

bool t代表区间内是否能含M。

如果不能含M的话有 res=min{f[l][i][0]+r-i}。(i<r) (串长的最小值等于前面串压缩后的最小值和不压缩后面串的长度)。

如果字符串长度为偶数,且前半串等于后半串,还有 f[l][r][t]=min(f[l][(l+r)>>1][t]+1) (后半串用1个R替代)。

如果t=1时,除上面俩个还有res=min{f[l][i][1]+1+f[i+1][r][1]}。

状态和3种状态转移方程比较难想。很大程度是因为对区间dp不熟悉。

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn = 50 + 10;
int f[maxn][maxn][2];
char s[100];

bool same(int l,int r) {
    int n=r-l+1;
    if(n%2) return 0;
    int mid=(l+r)>>1;
    for(int i=l,j=mid+1;i<=mid;i++,j++) if(s[i]!=s[j]) return 0;
    return 1;
}

int dp(int l,int r,bool t) {
    if(l==r) return 1;
    if(f[l][r][t]) return f[l][r][t];
    int &res=f[l][r][t];
    res=r-l+1;
    if(t) for(int i=l;i<r;i++) res=min(res,dp(l,i,1)+dp(i+1,r,1)+1);
    for(int i=l;i<r;i++) res=min(res,dp(l,i,t)+r-i);
    if(same(l,r)) res=min(res,dp(l,(l+r)>>1,0)+1);    
    return res;
}

int main() {
    scanf("%s",s+1);
    printf("%d\n",dp(1,strlen(s+1),1));
    return 0;
}
posted @ 2016-07-12 00:29  invoid  阅读(...)  评论(...编辑  收藏