String painter
Time Limit: 5000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1482 Accepted Submission(s): 644
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
Source
Recommend
题意:给定两个相同长度的字符串A,B,每次操作可以使一个区间[l,r]变成同一个字符,问最少需要多少次操作时A变成B。
思路:
我们先考虑这样一个问题:假如A是空串,A最少需要多少次操作变成B。不难想到区间dp,设dp[i][j]为将A区间[i,j]染成B的最少操作数,那么dp[i][j]分为两部分;(1)dp[i][j]=min(dp[i][j],dp[i+1][j]+(B[i]==B[i+1]?0:1) ) (2)dp[i][j]=min(dp[i][j],dp[i][k-1]+dp[k+1][j]) 其中k满足B[i]==B[k] 且 i<k<=j。
再考虑A串,设f[i]表示A[0]~A[i]==B[0]~B[i]的最小操作数,初始化时假设A与B没有一个字符对应相同,即f[i]=dp[0][i] , f[0]特殊处理,f[0]=A[0]==B[0]?0:1; 那么f[i]考虑两部分,(1) f[i]=min(f[i-1],f[i]) ,A[I]==B[i] (2) f[i]=min( f[i] ,f[j] +dp[j+1][i]) 其中0<=j<i ; 对(2)我们可以这样理解:将[j+1,r]视作空串。详见程序:
记忆化搜索:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN=100+100;
const int inf=0x3fffffff;
int n;
int ans[MAXN],dp[MAXN][MAXN];
char s1[MAXN],s2[MAXN];
void dfs(int i,int j)
{
if(j<=i)
{
dp[i][j]=j-i+1;
return;
}
if(dp[i][j]!=-1)
return ;
dfs(i+1,j);
dp[i][j]=dp[i+1][j]+(s2[i]==s2[i+1]?0:1);
for(int k=i+1;k<=j;k++)
if(s2[i]==s2[k])
{
dfs(i,k-1); dfs(k+1,j);
if(dp[i][k-1]+dp[k+1][j]<dp[i][j]||dp[i][j]==-1)
dp[i][j]=dp[i][k-1]+dp[k+1][j];
}
}
int main()
{
//freopen("text.txt","r",stdin);
while(~scanf("%s%s",s1,s2))
{
int n=strlen(s2);
memset(dp,-1,sizeof(dp));
for(int i=0;i<n;i++)
dp[i][i]=1;
for(int i=0;i<n;i++)
for(int j=i;j<n;j++)
if(dp[i][j]==-1)
dfs(i,j);
for(int i=0;i<n;i++)
{
ans[i]=dp[0][i];
if(s1[i]==s2[i])
{
if(i==0)
ans[i]=0;
else
ans[i]=ans[i-1];
}
for(int j=0;j<i;j++)
ans[i]=min(ans[i],ans[j]+dp[j+1][i]);
}
printf("%d\n",ans[n-1]);
}
return 0;
}
线性:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN=100+100;
int n;
int ans[MAXN],dp[MAXN][MAXN];
char s1[MAXN],s2[MAXN];
int main()
{
//freopen("text.txt","r",stdin);
while(~scanf("%s%s",s1,s2))
{
int n=strlen(s2);
memset(dp,0,sizeof(dp));
for(int i=0;i<n;i++)
for(int j=i;j<n;j++)
dp[i][j]=j-i+1;
for(int i=n-2;i>=0;i--)
for(int j=i+1;j<n;j++)
{
dp[i][j]=dp[i+1][j]+(s2[i]==s2[i+1]?0:1);
for(int k=i+1;k<=j;k++)
if(s2[i]==s2[k])
dp[i][j]=min(dp[i][j],dp[i][k-1]+dp[k+1][j]);
}
for(int i=0;i<n;i++)
printf("%d ",dp[0][i]);
printf("\n");
for(int i=0;i<n;i++)
{
ans[i]=dp[0][i];
if(s1[i]==s2[i])
{
if(i==0)
ans[i]=0;
else
ans[i]=ans[i-1];
}
for(int j=0;j<i;j++)
ans[i]=min(ans[i],ans[j]+dp[j+1][i]);
}
printf("%d\n",ans[n-1]);
}
return 0;
}