bzoj1260: [CQOI2007]涂色paint

区间dp。

用f[l][r]表示从l到r最少需要染几次色。

状态转移方程:

1.f[l][r]=min(f[l][i],f[i+1][r]) (l<=i<r) 这段染色等于俩段分别染色,很好看出来。

2.if(s[l]==s[r]) f[l][r]=min(min(f[l+1][r],f[l][r+1]),f[l+1][r-1])。

分俩种一可以直接涂上俩端点,2是可以忽略掉左端点和右端点。

第2点作用是很关键的,它会解决类似ABACDA之类的问题。忽略掉一段端点之后就可以继续找俩个端点进行染色。

为什么是对的呢?因为最后无论如何都一个节点都需要涂一次,所有的同色的端点就也被涂了。

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn = 200 + 10;

int n;
int f[maxn][maxn];
char s[maxn];

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

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