hdu 2476 String painter(区间dp)

String painter

Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 2580    Accepted Submission(s): 1165


Problem 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
 

题意就是,给你两个串,每次你可以在第一个串中选择一段连续的区间,把这个区间 里每个字母都变成一个相同的字母,问你最少需要多少次操作,才能把第一个串变成第二个串。

区间dp,dp有三维,dp[l][r][k]表示区间[l,r]全被变成了字母k之后,变成字符串2所需要的最少的步骤,如果k=26的话,就表示这个区间没有改变,这个区间里所有的字母都是字符串1原来的样子,然后就是dp的状态转移了,首先我们知道,当k=26的时候,如果s1[l]==s2[l]或者s1[r]==s2[r],那么就可以直接不用考虑第l个或者第r个了,当k!=26的时候,我们就看s1[l]和s1[r]被改变之后的字母是不是就是最终我们要变得字母,要是是的话,情况就和之前说的那个一样,就可以不用考虑了。除此之外,我们还要枚举把这个区间分成两个区间分别进行改变的时候的情况,其实区间dp,这一步是很常见的,我就不多少了,最后dp[l][r][x]就等于之前说的这些情况中的最小值,最后的答案就是dp[0][len-1][26],具体的细节,看代码就好了。

我的方法和网上做的方法不一样,网上的都是二维的做法,但是代码更长,而且我觉得更难想,他们是先不管原来的串,就是把原来的串当成是空白串,算出每个区间变成目标区间所需要的最小步数,然后再接着操作,大家可以去看看,我一开始也是照着题解上的那种方法敲的,觉得好麻烦,所以我最终还是按照我自己原先的思路a了这道题,而且我觉得我的想法比较好理解一点吧,代码也比较短,下面是代码。


#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;

const int maxn = 110;
const int INF = 1e9;
int dp[maxn][maxn][30];
char s1[maxn],s2[maxn];

int slove(int l,int r,int x){
    if(l>r) return 0;
    if(dp[l][r][x]!=-1) return dp[l][r][x];
    int ans=INF;
    ans=min(slove(l+1,r,x),slove(l,r-1,x))+1;
    if(x==26&&s1[l]==s2[l] || s2[l]-'a'==x) ans=min(ans,slove(l+1,r,x));
    if(x==26&&s1[r]==s2[r] || s2[r]-'a'==x) ans=min(ans,slove(l,r-1,x));
    if(s2[l]==s2[r]) ans=min(ans,slove(l+1,r-1,s2[l]-'a')+1);
    for(int i=l;i<r;i++)
        ans=min(ans,slove(l,i,x)+slove(i+1,r,x));
    return dp[l][r][x]=ans;
}

int main()
{
    while(scanf("%s %s",s1,s2)!=-1){
        int len=strlen(s1);
        memset(dp,-1,sizeof(dp));
        printf("%d\n",slove(0,len-1,26));
    }
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值