String painter HDU - 2476 (区间DP)

String painter

 题目链接:HDU - 2476 

题意:给你两个长度相同的字符串A, B, 要求把字符串A变为字符串B,每次只能选中一个区间[l, r], 将区间内的所有字符全部变为一种字符;问最少需要操作几次能把A转化成B;

思路:直接将A转化成B不好办,我们可以先将一个空串转化成B,再比较将A直接妆化成B那个更快;

令dp[i][j]为将[i, j]区间转换成功最少操作数;

最坏的情况下,是将每个字符都变一下,dp[i][i]=1;区间[i, i+1]是由[i, i]扩展来的,dp[i][i+1]=dp[i][i]+1;同理:dp[i][j]=dp[i][j-1]+1;然后在区间[i, j]中如果有一个B[k]==B[j]那么dp[i][j]=min(dp[i][j], dp[i][k-1]+dp[k][j-1]);这一步是如何来的呢?

如图所示[i, j]区间可以看作[i, k-1]+[k, j-1],因为B[j]==B[k],所以先[k, j]全转换成1种字符,再将[k+1, j-1]转换,相当于只转化了[k, j-1];

注意,这里不要写成dp[k+1][j-1]+1, 因为dp[k][j-1]可能更小;

下一步的工作就是看看A直接转换成B是否更快?

令ans[i]表示A的[0, i]区间转换成B的[0, i]的最少操作;

最坏情况下,A->B,相当于空串->B;ans[i]=dp[0][i];

如果A[i]==B[i] , ans[i]=ans[i-1];这一步其实也很容易理解,i处的字符相等,那么就不需要转化了,只要转化前i-1字符;需要注意的是:如果i=0,ans[i]=0;因为i-1=-1;不能做数组下标,没有ans[-1];

[0, i]转换后,看看还有没有更简便的;

ans[i]=min(ans[i], ans[k]+dp[k+1][i])(0<=k<=i);

#include <bits/stdc++.h>
using namespace std;
int main(){
	char A[110], B[110];
	int dp[110][110], ans[110];
	while(~scanf("%s%s", A, B)){
		memset(dp, 0, sizeof(dp));
		int len=strlen(A);
		for(int i=0; i<len; i++) dp[i][i]=1;
		for(int l=2; l<=len; l++){
			for(int i=0; i+l<=len; i++){
				int j=l+i-1;
				dp[i][j]=dp[i][j-1]+1;
				for(int k=i; k<j; k++){
					if(B[j]==B[k]){
						dp[i][j]=min(dp[i][j], dp[i][k-1]+dp[k][j-1]);
					}
				}
			}
		}
		for(int i=0; i<len; i++){
			ans[i]=dp[0][i];
			if(A[i]==B[i]){
				if(i==0) ans[i]=0;
				else ans[i]=ans[i-1];
			}
			for(int k=0; k<=i; k++){
				ans[i]=min(ans[i], ans[k]+dp[k+1][i]);
			}
		}
		printf("%d\n", ans[len-1]);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Sirius_han/article/details/81323901