题目大意:给你两个字符串,有一个刷子,每次能够把一段连续的字符改为同一个字符,问你将a字符串最少改变几次变成b字符串?
思路:比较明显的区间DP,但是直接考虑两个字符串很难考虑,先考虑如果a为空串,设d[ i ][ i ] 为从第i个字符到第j个字符从空串变为b字符串的最小步数,考虑最左边的i字符,那么d[ i ][ j ] = min(d[ i + 1][ j ] ,d[i+1][ k ] + d[ k+1 ][ j ] (if b[ i ] == b[ k ]))。之后,再来考虑本来的a字符串,设ans[ i ] 表示由a变为b最少需要几步,那么ans[ i ] = min(d[ 0 ][ i ],ans[ j ] + d[ j+ 1][ i ],ans[ i - 1](if(a[ i ] == b[ i ])) )。
很好的题目,自己想不到,mark一下,学习了~~
代码如下:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN = 111 ;
char str1[MAXN],str2[MAXN];
int d[MAXN][MAXN];
void dp(int l,int r)
{
if(l==r)
{
d[l][r] = 1;
return ;
}
d[l][r] = d[l+1][r] + 1;
for(int i =l+1;i<=r;i++)
if(str2[l]==str2[i])
d[l][r] = min(d[l][r] , d[l+1][i] + d[i+1][r]);
}
int ans[MAXN];
int main()
{
while(~scanf("%s%s",str1,str2))
{
memset(d,0,sizeof(d));
int len = strlen(str1);
for(int dis = 1;dis<=len;dis++)
{
for(int i = 0;i<len;i++)
{
int j = i+dis-1;
if(j>=len) break;
dp(i,j);
//printf("d[%d][%d] = %d\n",i,j,d[i][j]);
}
}
//printf("%d\n",d[0][len-1]);
for(int i = 0;i<len;i++)
{
ans[i] = d[0][i];
if(str1[i]==str2[i])
ans[i] = min(ans[i],(i==0 ? 0: ans[i-1]));
for(int j =0 ;j<i;j++)
ans[i] = min(ans[i],ans[j] + d[j+1][i]);
}
printf("%d\n",ans[len-1]);
}
return 0;
}