bzoj 1260 (区间dp)

传送门

题意:

给你一串由大写字符组成的长度为\(n\)字符串,现在你每次可以让区间\([l,r]\)的所有字符变成任意一种字符。现在问你把一个长度为\(n\)的空串变为指定的字符串需要多少多少次操作。

分析:

这个问题在基础区间dp中夹杂了贪心的思想。

我们考虑\(dp[l][r]\)为区间\([l,r]\)进行染色取得了对应的值的最小的操作数。在此基础上,我们贪心的考虑,对于一个大的区间\([l,r]\),倘若区间两端的字符是相同的,即\(str[l]==str[r]\),要使得答案更优,则这个大的区间只需要通过子区间\([l+1,r]\)或者子区间\([l,r-1]\),通过染成同一种颜色,花费\(1\)点代价转移而来。而倘若区间两端的字符不相同,则这段区间是由这段区间的两个子区间转移而来的,此时我们只需要用最基本的区间dp的讨论,通过枚举断点\(k\)进行状态转移。

代码:

#include <bits/stdc++.h>
#define maxn 105
using namespace std;
int dp[maxn][maxn],a[maxn];
char str[maxn];
const int inf=0x3f3f3f3f;
int main()
{
    scanf("%s",str+1);
    int n=strlen(str+1);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            dp[i][j]=inf;
    for(int i=1;i<=n;i++){
        dp[i][i]=1;
    }
    for(int p=1;p<=n;p++){
        for(int i=1,j=i+p;j<=n&&i<=n;i++,j=i+p){
            if(str[i]==str[j]) dp[i][j]=min(dp[i+1][j],dp[i][j-1]);
            else
                for(int k=i;k<j;k++){
                    dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]);
                }
        }
    }
    printf("%d\n",dp[1][n]);
    return 0;
}

posted @ 2019-07-19 23:56  ChenJr  阅读(170)  评论(0编辑  收藏  举报