HDU_2476_String painter_(区间dp)

String painter

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


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
 
2017.3.18复习,感觉这道题的dp设计很巧妙,还是没有吃透。。。

 
题意:给定两个等长字符串A、B,一次操作可以将A的任意一段连续的字符变为同一任意字符,问最少多少次操作可以将A变为B。
 
专门挑的区间dp的题,但是然并卵。。。没思路啊。。。看题解。。。
 
思路:dp[i][j]:将空串变为B[i-->j]所需要的最少次数。先求出所有dp[i][j],即求出将空串变为B[i-->j]所需最少次数。那么根据dp数组求出最终答案就很容易:
1.ans[k]=dp[1][k]
 
2.if(A[k]==B[k])   ans[k]=ans[k-1];     (ans[0]==0)
 else  ans[k]=min(ans[k],ans[t]+ans[t+1][k]);  (1=<t<k)
 
求dp[i][j]:
枚举起点i、终点j、遍历[i+1,j]区间k

for(int j=1;j<=len;j++) //end
{
  for(int i=j;i>0;i--) //begin
  {
    dp[i][j]=dp[i+1][j]+1;
    for(int k=i+1;k<=j;k++)
      if(B[i]==B[k])
        dp[i][j]=min(dp[i][j],dp[i][k-1]+dp[k+1][j]);
   }
}

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

char A[105],B[105];
int dp[105][105];
int ans[105];

int main()
{
    while(scanf("%s%s",A+1,B+1)!=EOF)
    {
        memset(dp,0,sizeof(dp));
        memset(ans,0,sizeof(ans));
        int len=strlen(B+1);
        for(int j=1;j<=len;j++)  //end
        {
            for(int i=j;i>0;i--)  //begin
            {
                dp[i][j]=dp[i+1][j]+1;
                for(int k=i+1;k<=j;k++)  //一定是从左往右找重的
                    if(B[i]==B[k])
                        dp[i][j]=min(dp[i][j],dp[i][k-1]+dp[k+1][j]);
            }
        }
        for(int i=1;i<=len;i++)
        {
            ans[i]=dp[1][i];
            if(A[i]==B[i])
                ans[i]=ans[i-1];
            else
            {
                for(int j=1;j<i;j++)
                    ans[i]=min(ans[i],ans[j]+dp[j+1][i]);
            }
        }
        printf("%d
",ans[len]);
    }
    return 0;
}

 

 

原文地址:https://www.cnblogs.com/jasonlixuetao/p/6503388.html