Description
Input
The first line contains string A.
The second line contains string B.
The length of both strings will not be greater than 100.
Output
Sample Input
zzzzzfzzzzz abcdefedcba abababababab cdcdcdcdcdcd
Sample Output
6 7
题意:
给出两个字符串s1,s2。对于每次操作可以将 s1 串中的任意一个子段变成另一个字符。问最少需要多少步操作能将s1串变为s2串。
思路:
首先我们应该关心的是s2串是怎么由一个空串变来的,我们先认为s1和s2任何一个字符都不相等,那么用dp[i][j]来表示要变成s2串 i~j 所需要的最少操作步数。
如果不考虑颜色重复利用的情况(例如 aba 应该先变成 aaa 再变成 aba 只消耗两步),那么考虑第 i 个元素,一定是有 dp[i][j] = dp[i+1][j] + 1;
如果考虑在区间 i~j 中可能会有 元素 k 与 元素 i 相同,即 i 或许能和其他元素一起变,那么区间 i ~ j 就被拆成 i~k 和 k+1 ~ j ,因为元素 i 可以和元素 k 共用,所以计算时有 dp[i][j] = min(dp[i][j],dp[i+1][k] + dp[k+1][j]);
在得到了一个s2串的相关dp数组后,我们考虑s1串,如果s1串和s2串在某一个点相等了,即表示这一点可以不用特意去刷一次,那么便可以由这一点来分成两个区间。
如果用 ans[i]来记录0~i这个区间的最终答案,那么我们需要将其初始化为 ans[i] = dp[0][i];(假设s1串与s2串完全不同)。
如果发现了s1[i] == s2[i],那么显然有 ans[i] = min(ans[i],ans[i-1]); (因为这一点其实可以不刷)
如果不相等,我们也可以在前i个元素中寻找一个断点来将答案优化。(因为一个大区间的最优解可能由两个小区间的最优解组成)。即
ans[i] = min(ans[i],ans[j] + dp[j+1][i]);
#include"iostream"
#include"cstring"
#include"cstdio"
#include"algorithm"
using namespace std;
char s1[105];
char s2[105];
int dp[105][105];
int ans[105];
int main(void)
{
while(~scanf("%s%s",s1,s2))
{
int siz = strlen(s1);
memset(dp,0,sizeof(dp));
for(int i = 0;i < siz;i++) dp[i][i] = 1;
for(int j = 0;j < siz;j++)
{
for(int i = j - 1;i >= 0;i--)
{
dp[i][j] = dp[i+1][j] + 1;
for(int k = i + 1;k <= j;k++)
{
if(s2[i] == s2[k])
dp[i][j] = min(dp[i][j] , dp[i+1][k] + dp[k+1][j]);
}
}
}
for(int i = 0;i < siz;i++)
ans[i] = dp[0][i];
if(s1[0] == s2[0]) ans[0] = 0;
for(int i = 1;i < siz;i++)
{
if(s2[i] == s1[i])
ans[i] = min(ans[i],ans[i-1]);
else
{
for(int j = 0;j < i;j++)
ans[i] = min(ans[i],ans[j] + dp[j+1][i]);
}
}
printf("%d\n",ans[siz-1]);
}
return 0;
}