[一道区间dp][String painter]

http://acm.hdu.edu.cn/showproblem.php?pid=2476

String painter

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


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

 题意:有两个字符串,A串和B串,每次可以对A串一个区间进行涂改,使该区间所有字母变成任意一种字母,求使A串变成B串需要的最少操作次数

题解:首先考虑一个简化的问题,把一个空串涂改成B串需要的操作数,显然可以通过最基本的区间dp进行解决,转移方程为if(B[i]==B[k])dp[i][j]=min(dp[i][j],dp[i][k-1]+dp[k+1][j]);else dp[i][j]=min(dp[i][j],min(dp[i][k]+dp[k+1][j],dp[i][k-1]+dp[k][j]));然后考虑A串不是空串,那么如果A[i]==B[i],则有ans[i]=ans[i-1],如果A[i]!=B[i],那么ans[i]=min(ans[j]+dp[j][i])。

普通的循环迭代版本

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define debug(x) cout<<"["<<#x<<"]"<<" is "<<x<<endl;
 4 char ch[105],ch2[105];
 5 int dp[105][105],ans[105];
 6 const int inf=1e8;
 7 int main(){
 8     while(scanf("%s",ch+1)!=EOF){
 9         scanf("%s",ch2+1);
10         int len=strlen(ch+1);
11         for(int i=1;i<=len;i++){
12             for(int j=1;j<=len;j++){
13                 if(i>j)dp[i][j]=0;
14                 else if(i==j)dp[i][j]=1;
15                 else dp[i][j]=inf;
16             }
17         }
18         for(int i=2;i<=len;i++){
19             for(int j=1;j+i-1<=len;j++){
20                 for(int k=j+1;k<=j+i-1;k++){
21                     if(ch2[j]==ch2[k])dp[j][j+i-1]=min(dp[j][j+i-1],dp[j][k-1]+dp[k+1][j+i-1]);
22                     else dp[j][j+i-1]=min(dp[j][j+i-1],min(dp[j][k]+dp[k+1][j+i-1],dp[j][k-1]+dp[k][j+i-1]));
23                 }
24             }
25         }
26         for(int i=1;i<=len+1;i++){
27             ans[i]=inf;
28         }
29         ans[1]=0;
30         for(int i=1;i<=len;i++){
31             if(ch[i]==ch2[i]){
32                 ans[i+1]=min(ans[i+1],ans[i]);
33             }
34             else{
35                 for(int j=1;j<=i;j++){
36                     ans[i+1]=min(ans[i+1],ans[j]+dp[j][i]);
37                 }
38             }
39         }
40         printf("%d
",ans[len+1]);
41     }
42     return 0;
43 }
View Code

记忆化搜索版本(注意由于sol(1,len)只能保证dp[1][len]被更新,而不能保证所有的dp[i][j]被遍历到,所以需要使用n^2次sol(i,j)保证所有dp[i][j]都被更新了而不再是初始值)

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define debug(x) cout<<"["<<#x<<"]"<<" is "<<x<<endl;
 4 char ch[105],ch2[105];
 5 int dp[105][105],ans[105];
 6 const int inf=1e8;
 7 int sol(int l,int r){
 8     if(dp[l][r]!=0x3f3f3f3f)return dp[l][r];
 9     if(l>r)return dp[l][r]=0;
10     if(l==r)return dp[l][r]=1;
11     for(int k=l+1;k<=r;k++){
12         if(ch2[k]==ch2[l]){
13             dp[l][r]=min(dp[l][r],sol(l+1,k)+sol(k+1,r));
14         }
15         else{
16             dp[l][r]=min(dp[l][r],sol(l+1,r)+1);
17         }
18     }
19     return dp[l][r];
20 }
21 int main(){
22     while(scanf("%s",ch+1)!=EOF){
23         scanf("%s",ch2+1);
24         int len=strlen(ch+1);
25         memset(dp,0x3f3f3f3f,sizeof(dp));
26         for(int i=1;i<=len;i++){
27             for(int j=i;j<=len;j++){
28                 sol(i,j);
29             }
30         }
31        // sol(1,len);
32         for(int i=1;i<=len+1;i++){
33             ans[i]=0x3f3f3f3f;
34         }
35         ans[1]=0;
36         for(int i=1;i<=len;i++){
37             if(ch[i]==ch2[i]){
38                 ans[i+1]=min(ans[i+1],ans[i]);
39             }
40             else{
41                 for(int j=1;j<=i;j++){
42                     ans[i+1]=min(ans[i+1],ans[j]+dp[j][i]);
43                 }
44             }
45         }
46         printf("%d
",ans[len+1]);
47     }
48     return 0;
49 }
View Code
原文地址:https://www.cnblogs.com/MekakuCityActor/p/10808584.html