hdu 2476 String painter(区间qp)

String painter

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



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
 

Source
2008 Asia Regional Chengdu


题意:给你两个字符串,求出第一串改成第二串的最小步数,修改的方式是你可以选择任意区间,将其中所有字母修改成同一个字母。

思路:
       毫无疑问是区间dp,但是怎么写出表达式是一个很严肃的问题o( ̄▽ ̄)do( ̄▽ ̄)do( ̄▽ ̄)d
     
      由空串修改成第二串这个区间dp还是很好写的,个人觉得下面的那个转化才是神奇。
      空串转化第二串,度娘给我的那个确实不错,但是我估计比较笨,想不到那种转化。 
    当然学习一下还是非常有必要的,说不定什么时候用上了呢。。
    
for(j = 0; j<len; j++)  
        {  
            for(i = j; i>=0; i--)//j为尾,i为头  
            {  
                dp[i][j] = dp[i+1][j]+1;//先每个单独刷  
                for(k = i+1; k<=j; k++)//i到j中间所有的刷法  
                {  
                    if(s2[i]==s2[k])  
                        dp[i][j] = min(dp[i][j],(dp[i+1][k]+dp[k+1][j]));//i与k相同,寻找i刷到k的最优方案  
                }  
            }  
        }  

这里,当i和k位置字符相同时,有dp[i+1][k]+dp[k+1][j] 取最小,这就是精髓所在了。
看清楚,这里是dp[i+1][k],和dp[i][k]有区别,就这一个区别,顿时不一样了,因为相等,所以i可以和k同刷,即dp[i][k]==dp[i+1][k];

这个dp就很清晰很明了了。

我没想到,所以,自己写了一个搓逼代码,那可真是挫orz
 for(int len=2;len<=n;len++)
        {
            for(int l=0;l+len-1<n;l++)
            {
                int r=l+len-1;
                if(s[l]==s[l+1])
                    dp[l][r]=dp[l+1][r];
                else if(s[r]==s[r-1])
                    dp[l][r]=dp[l][r-1];
                else if(s[l]==s[r])
                {
                    dp[l][r]=dp[l+1][r-1]+1;
                    for(int k=1;k<r;k++)
                    if(s[l]==s[k])
                       dp[l][r]=min(dp[l][r],dp[l][k]+dp[k][r]-1);
                }
                for(int k=l;k<r;k++)
                {
                    dp[l][r]=min(dp[l][r],dp[l][k]+dp[k+1][r]);
                }
            }
        }

这就是中规中矩的区间dp,毫无创意的搓逼代码。。。对比一下,多余内容好多,就不解释了,只是想证明一下自己的搓逼本质,吐血ing.

最重要的还是下面的由空串如何替换成第一串
代码:
      for(int i=0;i<n;i++)
         res[i]=dp[0][i];

       for(int i=0;i<n;i++)
       {
           if(s[i]==s1[i])
           {
               if(i==0)
                   res[i]=0;
               else
                   res[i]=res[i-1];
           }
           else
           {
               for(int j=0;j<i;j++)
                   res[i]=min(res[i],res[j]+dp[j+1][i]);
           }
       }


这也是一个牛逼的dp呀。
显而易见的这里只计算从[0,i]的转化。
ans[i]代表的是[0,i]的最小转化步数。
当是s1[i]==s2[i]时,直接等于前一步。
不等的时候,如代码所示。
神奇,神奇,神奇.......


 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值