[一道区间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.
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\n",ans[len+1]); 41 } 42 return 0; 43 }
记忆化搜索版本(注意由于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\n",ans[len+1]); 47 } 48 return 0; 49 }