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;
}