String painter LA 4394 区间dp

LA 4394

题意:给两个长度相等的字符串s,t,每步可以把s的一个连续子串刷成同一个字母,问至少需要多少步才能把s变成t。

思路:借鉴了别人的思想 :HyogaHyoga,首先求出一个空串(长度等于t不过元素为空)需要多少步才能变成t,设d[i][j]为从i到j至少需要多少步,d[i][j]的下一个状态显然有d[i+1][j]和d[i][j-1],当t[i]=t[j]时d[i][j]=d[i+1][j],不等于时还要加个1,如果存在一个k(i<k<j)使得t[i]=t[k]或者t[j]=t[k],那么d[i][j]=min(d[i][j],d[i][k-1]+d[k+1][j]),可用记忆化搜索搞定d数组,然后再求答案f数组,设f[i]为从0到i,s[i]经过最少f[i]步可以变成t[i],很容易发现当s[i]=t[i]时,f[i]=f[i-1],否则f[i]=min{d[0][i],f[j]+d[j+1][i]}

#include<stdio.h>
#include<string.h>
#define max(x,y) x>y?x:y
#define min(x,y) x<y?x:y
char s[1000],t[1000];
int d[101][101],f[101]; 
int dp(int i,int j)
{
	if(d[i][j])
	return d[i][j];
	if(i==j)
	return d[i][j]=1;
	int temp=(t[i]==t[j]?0:1);
	d[i][j]=min(dp(i+1,j)+temp,dp(i,j-1)+temp);
	for(int k=i+1;k<j;k++)
	{
		if(t[k]==t[i])
		d[i][j]=min(d[i][j],dp(i+1,k)+dp(k+1,j));
		if(t[k]==t[j])
		d[i][j]=min(d[i][j],dp(i,k-1)+dp(k+1,j));
	}
	return d[i][j];
}
int main()
{
	while(~scanf("%s%s",s,t))
	{
		int i,j,k;
		memset(d,0,sizeof(d));
		k=strlen(t);
		dp(0,k-1);
		if(s[0]==t[0])
		f[0]=0;
		else
		f[0]=1;
		for(i=1;i<k;i++)
		{
			f[i]=d[0][i];
			if(s[i]==t[i])
			f[i]=f[i-1];
			else  
			for(j=0;j<i;j++)
			f[i]=min(f[j]+d[j+1][i],f[i]);
		}
		printf("%d\n",f[k-1]);		
	}
}

猜你喜欢

转载自blog.csdn.net/ccsu_cat/article/details/80100771