题目链接:https://vjudge.net/contest/308310#problem/H
题目大意:给出两个字符串,每次我们可以把一个字符串的一个区间刷成同一个字母(每次修改区间[L, R]全部为同一个字符),问最少多少步可以把第一个字符串变为第二个字符串。

例如zzzzzfzzzzz,长度为11,我们就将下标看做0~10

先将0~10刷一次,变成aaaaaaaaaaa

1~9刷一次,abbbbbbbbba

2~8:abcccccccba

3~7:abcdddddcba

4~6:abcdeeedcab

5:abcdefedcab

这样就6次,变成了s2串了

思路:此题分两步,第一步是假设由空串变成b串,进行区间dp,dp[i][j]代表把区间[i,j]变到与目标串相同的时候最少需要的步数,所以可以初始化dp[i][j]=dp[i+1][j]+1;

然后如果str2[i]==str2[k]就可以有dp[i][j]=min(dp[i][j],dp[i+1][k]+dp[k+1][j])。

然后用ans[i]:代表把前i个a[i]字符刷成b。需要的最小步数。

for(int i=1;i<=n;i++)
{
   if(s1[i]==s2[i])
   {
       ans[i]=ans[i-1];
   }
   else
   {
       for(int k=1;k<i;k++)
       {
           ans[i]=min(ans[i], ans[k]+dp[k+1][i]);
       }
   }
}

全部代码:

#include <bits/stdc++.h>
using namespace std;

char s1[105];
char s2[105];
int dp[105][105];
int ans[105];
int main()
{
    while(scanf("%s",s1+1)!=EOF)
    {
        memset(dp, 0, sizeof(dp));
        memset(ans, 0, sizeof(ans));
        scanf("%s", s2+1);
        int n=strlen(s1+1);

        for(int Len=1;Len<=n;Len++)
        {
            for(int L=1;L+Len-1<=n;L++)
            {
                int R=L+Len-1;
                dp[L][R]=dp[L+1][R]+1;

                for(int k=L+1;k<=R;k++)//枚举可能相等的位置
                {
                    if(s2[L]==s2[k])
                    {
                        dp[L][R]=min(dp[L][R], dp[L+1][k]+dp[k+1][R]);
                    }
                }
            }

        }

        ans[0]=0;
        for(int i=1;i<=n;i++)
        {
            ans[i]=dp[1][i];
        }

        for(int i=1;i<=n;i++)
        {
            if(s1[i]==s2[i])
            {
                ans[i]=ans[i-1];
            }
            else
            {
                for(int k=1;k<i;k++)
                {
                    ans[i]=min(ans[i], ans[k]+dp[k+1][i]);
                }
            }
        }

        printf("%d\n",ans[n]);
    }

    return 0;
}