String painter
Time Limit: 5000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 4208 Accepted Submission(s): 1960
The first line contains string A.
The second line contains string B.
The length of both strings will not be greater than 100.
zzzzzfzzzzz abcdefedcba abababababab cdcdcdcdcdcd
6 7
题目大意:
给你两个字符串,A和B,每一次我们可以使用一种颜色(用字母代替)刷任意位子的连续子序列,问将字符串A变成字符串B最少需要刷多少次。
思路:
1、考虑到要求最小步数,考虑dp.观察到数据范围,考虑区间dp.
一开始设定dp【i】【j】表示使得区间【i,j】的A串变成B串的最小步数转移和结果相对很难得到。写了半天样例也是搞不过去。
后来反应过来,我们不妨设定dp【i】【j】表示将一个空串区间【i,j】刷成B字符串的最小步数。
那么对应我们再处理哪里进行对A串的保留,哪里进行重新刷就行了。
整体思路确定如下:
①设定dp【i】【j】表示将一个空串区间【i,j】刷成B字符串的最小步数。
②设定F【i】表示将A串将区间【1,i】刷成B串需要的最小步数。
2、那么我们首先搞定区间dp的状态转移。
不难推出有四种转移方式:
注意区间合并操作之类的细节即可。
3、那么接下来搞定F【i】的状态转移:
①如果当前A【i】==B【i】.那么这一个位子是不需要重新刷的,那么对应有:f【i】=min(f【i】,f【i-1】);
②如果当前A【i】!=B【i】.那么我们枚举一个位子作为起点刷一个区间【j,i】即可,那么对应有:f【i】=min(f【i】,f【j】+dp【j+1】【i】);
Ac代码:
#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;
char a[150];
char b[150];
int dp[150][150];
int f[150];
int judge(int i,int j)
{
if(b[i]!=b[j])return 1;
else return 0;
}
int main()
{
while(~scanf("%s%s",a+1,b+1))
{
int n=strlen(a+1);
memset(dp,0,sizeof(dp));
memset(f,0,sizeof(f));
for(int len=0;len<=n;len++)
{
for(int i=1;i<=n;i++)
{
int j=i+len;
if(len==0)
{
dp[i][j]=1;
}
else if(j<=n)
{
dp[i][j]=0x3f3f3f3f;
if(i+1<=n)dp[i][j]=min(dp[i][j],dp[i+1][j]+judge(i,i+1));
if(i+1<=n)dp[i][j]=min(dp[i][j],dp[i+1][j]+judge(i,j));
if(j-1>=1)dp[i][j]=min(dp[i][j],dp[i][j-1]+judge(j-1,j));
if(j-1>=1)dp[i][j]=min(dp[i][j],dp[i][j-1]+judge(i,j));
for(int k=i;k<j;k++)
{
dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]);
}
}
}
}
for(int i=1;i<=n;i++)
{
f[i]=dp[1][i];
if(a[i]==b[i])f[i]=min(f[i-1],f[i]);
else
{
for(int j=0;j<i;j++)
{
f[i]=min(f[i],f[j]+dp[j+1][i]);
}
}
}
printf("%d\n",f[n]);
}
}