uva10739(DP 回文字符串)

题目的意思就是给你一个字符串,问你最少经过几次操作,能把它变成回文字符串.

操作有三种

1.在任意位置添加一个字符.

2.在任意位置删除一个字符;

3.替换掉任意一个字符;


首先我们的d[i][j]是指,将i到j之间的这个串变成回文最少要几步.

我们可以发现d[i][j]如果第i个字符,和第j个字符,是相同的.难么d[i][j] = d[i + 1][j - 1]也就是不管这两个相同的,往里面缩一位.

但是如果第i位和第j位不相同,那么我们就要比较了.

如果这两位不相同,我们有两种办法,

1.把左边那位删了,或者把右边那位删了(因为通过加上两位让他们边回文,开销肯定大,所以我们直接不考虑加.)axxxb ->xxxb

2.把左边那位变成右边那位,或者把右边那位,变成左边那位 axxxb ->bxxxb;

上面两种办法开销都是1次 ,我们我们比较  min (     d[i + 1][ j ]         ,   d[ i ] [ j - 1]  ,     d[  i + 1 ][ j - 1]  )   + 1;

最后如果 j - i < 1了,就返回0  ,因为只有1位了肯定是回文了呀,不需要操作...


AC代码:



#include
#include
const int N = 1005;
const int INF = 0x3f3f3f3f;
char str[N];
int d[N][N];
int dp(int l , int r) {
	int m;
	if(d[l][r] != -1)
		return d[l][r];
	if(r - l < 1) {
		d[l][r] = 0;
		return 0 ;
	}
	else if(str[l] == str[r]) {
		m = dp(l + 1 , r - 1);
	}
	else {
		m = INF;
		int a = dp(l + 1 , r) + 1;
		if(a < m)
			m = a;
		int b = dp(l , r - 1) + 1;
		if(b < m)
			m = b;
		int c = dp(l + 1 ,r - 1) + 1;
		if(c < m)
			m = c;
	}
	d[l][r] = m;
	return m;
}
int main () {
	int t;
	int cas = 1;
	scanf("%d",&t);
	while(t--) {
		memset(d ,-1 ,sizeof(d));
		scanf("%s",str);
		int len1 = 0;
		int len2 = strlen(str) - 1;
		printf("Case %d: %d\n",cas++ ,dp(len1 , len2));
	}
}



你可能感兴趣的:(DP)