(区间dp) hdu 2476 String painter

题目
hdu2476

题意:
给出字符串a和字符串b,你可以将字符串a的字符段更改为所需的任何其他字符。 输出字符串a更改为字符串b的最少次数。
更改操作:举个例子,在字符串 qwer 中,可以在字符段[0, 2](即字符段qwe)更改为字符 z,即 qwer → zzzr

思路:
可以拆成两步,第一步是把空串更改为字符串b,第二步是根据第一步的结果推导出字符串a更改为字符串b

空串更改为字符串b:
在区间 i ~ j 内,
如果字符串b [ i ] 在 区间 i+1 ~ j 内没有相同的字符,则
d p [ i ] [ j ] = d p [ i + 1 ] [ j ] + 1 dp [ i ] [ j ] = dp [ i + 1 ] [ j ] + 1 dp[i][j]=dp[i+1][j]+1
如果字符串b [ i ] 在 区间 i+1 ~ j 内有相同的字符,则
d p [ i ] [ j ] = min ⁡ k = i + 1 j d p [ i + 1 ] [ k ] + d p [ k + 1 ] [ j ] dp[i][j] = \min_{k=i+1}^{j} dp[i+1][k] + dp[k+1][j] dp[i][j]=k=i+1minjdp[i+1][k]+dp[k+1][j]

字符串a更改为字符串b:
一开始,ans [ j ] = dp [ 0 ] [ j ],ans [ 0 ] = (a [ 0 ] == b [ 0 ] ) ? 0 : 1;
在区间 0 ~ j 内,
如果字符串a [ j ] = b [ j ],则
a n s [ j ] = a n s [ j − 1 ] ans[j]=ans[j-1] ans[j]=ans[j1]
如果字符串a [ i ] != b [ i ],则
a n s [ j ] = min ⁡ k = 0 j a n s [ k ] + d p [ k + 1 ] [ j ] ans[j] = \min_{k=0}^{j} ans[k] + dp[k+1][j] ans[j]=k=0minjans[k]+dp[k+1][j]

as:accc 更改为 abbb 最少要改 1 次(从空串更改为 abbb 则要改 2 次)

代码

#include <iostream>
#include <algorithm>
#include <cstring>
#define DEBUG freopen("_in.txt", "r", stdin); freopen("_out1.txt", "w", stdout);
using namespace std;
const int MAXN = 110;
char a[MAXN], b[MAXN];
int dp[MAXN][MAXN], ans[MAXN];
int , s[MAXN][MAXN], v[200];  //s[i][j]:用二进制来保存字符串b在[i,j]的字符种类,v:记录 a ~ z 的二进制状态
void init(){
    
    
	for (int i = 0; i < 26; i++)
		v[i+'a'] = 1 << i;  //a:1, b:10, c:100...
}
void solve(){
    
    
	if (strcmp(a, b) == 0){
    
    
		printf("0\n");
		return;
	}
	int lena = strlen(a);
	for (int i = 0; i < lena; i++){
    
    
		dp[i][i] = 1;
		s[i][i] = v[b[i]];
	}
	for (int len = 1; len < lena; len++)
		for (int i = 0; i < lena - len; i++){
    
    
			int j = i + len;
			dp[i][j] = dp[i+1][j] + 1;
			if ((s[i+1][j] >> (b[i] - 'a')) & 1)  //字符串b[i] 在 区间 i+1 ~ j 内有相同的字符
				for (int k = i + 1; k <= j; k++)
					if (b[i] == b[k])
						dp[i][j] = min(dp[i][j], dp[i+1][k] + dp[k+1][j]);
			s[i][j] = s[i+1][j] | v[b[i]];  //更新状态
		}
	for (int i = 0; i < lena; i++)
		ans[i] = dp[0][i];
	ans[0] = (a[0] == b[0]) ? 0 : 1;
	for (int j = 1; j < lena; i++)
		if (a[j] == b[j])
			ans[j] = ans[j-1];
		else
			for (int k = 0; k <= j; k++)
				ans[j] = min(ans[j], ans[k] + dp[k+1][j]);
	printf("%d\n", ans[lena-1]);
}
int main(){
    
    
	init();
	while (~scanf("%s%s", a, b)) 
		solve();
	return 0;
}

猜你喜欢

转载自blog.csdn.net/ymxyld/article/details/113794491