bzoj1068: [SCOI2007]压缩

传送门
区间dp
f[i][j][k]表示从第i个到第j个字符,k=1表示前面是否有M
1.枚举分割点(k=1),转移方程min(f[i][l]+f[l+1][j]+1)(中间放一个M)
2.枚举分割点,仅对前面的部分压缩,转移方程min(f[i][l][k]+j-l)
3.判断当前部分是否能被压缩。转移方程min(f[i][(i+j)/2][0]+1)

#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
using namespace std;
int f[55][55][2],v[55][55][2],l;
char s[55];
void min(int &x,int y){
    if (y<x) x=y;
}
int same(int x,int y){
    if ((x+y+1)%2) return 0;
    int l=(y-x+1)/2;
    for (int i=1;i<=l;i++)
        if (s[x+i-1]!=s[x+i+l-1]) return 0;
    return 1;
}
int dp(int l,int r,int p){
    if (l==r) return 1;
    if (v[l][r][p]) return f[l][r][p];
    v[l][r][p]=1;
    f[l][r][p]=r-l+1;
    if (p) for (int i=l;i<r;i++) min(f[l][r][p],dp(l,i,1)+dp(i+1,r,1)+1);
    for (int i=l;i<r;i++) min(f[l][r][p],dp(l,i,p)+r-i);
    if (same(l,r)) min(f[l][r][p],dp(l,(l+r)/2,0)+1);
    return f[l][r][p];
}
int main(){
    scanf("%s",s+1);
    l=strlen(s+1);
    printf("%d",dp(1,l,1));
    return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值