String painter (hdu 2476)

F - String painter
Time Limit:2000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u
Appoint description: 

Description

There are two strings A and B with equal length. Both strings are made up of lower case letters. Now you have a powerful string painter. With the help of the painter, you can change a segment of characters of a string to any other character you want. That is, after using the painter, the segment is made up of only one kind of character. Now your task is to change A to B using string painter. What’s the minimum number of operations?
 

Input

Input contains multiple cases. Each case consists of two lines: 
The first line contains string A. 
The second line contains string B. 
The length of both strings will not be greater than 100. 
 

Output

A single line contains one integer representing the answer.
 

Sample Input

     
     
zzzzzfzzzzz abcdefedcba abababababab cdcdcdcdcdcd
 

Sample Output

     
     
6 7



题意:

给出两个字符串s1,s2。对于每次操作可以将 s1 串中的任意一个子段变成另一个字符。问最少需要多少步操作能将s1串变为s2串。


思路:

首先我们应该关心的是s2串是怎么由一个空串变来的,我们先认为s1和s2任何一个字符都不相等,那么用dp[i][j]来表示要变成s2串 i~j 所需要的最少操作步数。


如果不考虑颜色重复利用的情况(例如  aba  应该先变成 aaa 再变成 aba 只消耗两步),那么考虑第 i 个元素,一定是有 dp[i][j] = dp[i+1][j] + 1; 


如果考虑在区间 i~j 中可能会有 元素 k 与 元素 i 相同,即 i 或许能和其他元素一起变,那么区间 i ~ j 就被拆成 i~k 和 k+1 ~ j ,因为元素 i 可以和元素 k 共用,所以计算时有  dp[i][j] = min(dp[i][j],dp[i+1][k] + dp[k+1][j]);



在得到了一个s2串的相关dp数组后,我们考虑s1串,如果s1串和s2串在某一个点相等了,即表示这一点可以不用特意去刷一次,那么便可以由这一点来分成两个区间。


如果用 ans[i]来记录0~i这个区间的最终答案,那么我们需要将其初始化为 ans[i] = dp[0][i];(假设s1串与s2串完全不同)。


如果发现了s1[i] == s2[i],那么显然有 ans[i] = min(ans[i],ans[i-1]); (因为这一点其实可以不刷)


如果不相等,我们也可以在前i个元素中寻找一个断点来将答案优化。(因为一个大区间的最优解可能由两个小区间的最优解组成)。即

ans[i] = min(ans[i],ans[j] + dp[j+1][i]);


#include"iostream"
#include"cstring"
#include"cstdio"
#include"algorithm"

using namespace std;

char s1[105];
char s2[105];
int dp[105][105];
int ans[105];

int main(void)
{
    while(~scanf("%s%s",s1,s2))
    {
        int siz = strlen(s1);

        memset(dp,0,sizeof(dp));

        for(int i = 0;i < siz;i++) dp[i][i] = 1;

        for(int j = 0;j < siz;j++)
        {
            for(int i = j - 1;i >= 0;i--)
            {
                dp[i][j] = dp[i+1][j] + 1;

                for(int k = i + 1;k <= j;k++)
                {
                    if(s2[i] == s2[k])
                        dp[i][j] = min(dp[i][j] , dp[i+1][k] + dp[k+1][j]);
                }
            }
        }

        for(int i = 0;i < siz;i++)
            ans[i] = dp[0][i];
            
        if(s1[0] == s2[0]) ans[0] = 0;

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

        printf("%d\n",ans[siz-1]);
    }
    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值