首页 > 代码库 > uva10739String to Palindrome(递推)

uva10739String to Palindrome(递推)

题目:String to Palindrome


题目大意:给出一字符串,给你三种操作:可以将任何位置的字符删除,可以将任何位置的字符替换,可以在任何位置插入一个字符。问最少的操作能够把这个字符转换成回文。


解题思路:dp【i】【j】代表使字符串i到j位的子串变成回文的最少的操作。替换和删除还算好做,一开始一点都不知道插入该怎么办,后来看了别人的题解发现删除和插入是一样的效果。例如对于abbb字符串中的位置(1234)这个串,如果删除最后的那个b,那么就是dp【1】【3】 + 1.如果是在a的前面插入b,那么也是dp【1】【3】 + 1;所以这里只考虑删除。

递推的公式: s【i】 != s【j】, dp【i】【j】 = MIN (dp【i】【j - 1】 + 1, dp【i + 1】【j】 + 1,  dp【i + 1】【j - 1】+ 1)

                       s【i】 == s【j】, dp【i】【j】 = dp【i + 1】【j - 1】;

                       dp【i】【j - 1】 + 1: 把第j个字符删掉的情况。那么就是让i--j - 1的字符串成为回文的最少操作 + 1(删除操作)。

                       dp【i + 1】【j】 + 1:把第i个字符删掉的情况。同理。

                       dp【i + 1】【j - 1】  + 1 :把首位的字符其中一个替换。

                       计算顺序:长度小的先算。

代码:

#include <cstdio>
#include <cstring>

const int N = 1005;
int dp[N][N];
char str[N];

void init (int len) {
	
	for (int i = 0; i < len; i++) {
		
		dp[i][i] = 0;
		if (i + 1 < len) {

			if (str[i] == str[i + 1])
				dp[i][i + 1] = 0;
			else
				dp[i][i + 1] = 1;
		}
	}	
}

int Min (const int a, const int b) { return a < b ? a: b; }

int main () {

	int cas;
	int len;
	scanf ("%d", &cas);
	for (int k = 1; k <= cas; k++) {

		scanf ("%s", str);
		len = strlen (str);
		init (len);

		for (int n = 3; n <= len; n++) {
			for (int i = 0, j = n - 1; j < len; i++, j++) {

				if (str[i] == str[j])
					dp[i][j] = dp[i + 1][j - 1];
				else 
					dp[i][j] = Min (Min (dp[i + 1][j], dp[i][j - 1]), dp[i + 1][j - 1]) + 1; 

			}
		}

		printf ("Case %d: %d\n", k, dp[0][len - 1]);
	}
	return 0;
}