题目大意:给出一字符串,给你三种操作:可以将任何位置的字符删除,可以将任何位置的字符替换,可以在任何位置插入一个字符。问最少的操作能够把这个字符转换成回文。
解题思路: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; }
uva10739String to Palindrome(递推)
时间: 2024-10-02 22:53:16