// 400K 610MS G++ #include <stdio.h> #include <string.h> using namespace std; #define MAX 5005 // short DP[MAX][MAX]; int DP[MAX]; int tmp[MAX]; char str[MAX]; int length; // void solve() { // memset(DP, 0xff, sizeof(DP)); // for (int i = length-1; i >= 0; i--) { // for (int j = i; j <= length-1; j++) { // if (i == j) { // only 1 char, no // DP[i][j] = 0; // } else { // j > i // if (str[i] == str[j]) { // both 1st and last char equal // if (i+1 < j) { // if some char bertween i and j // DP[i][j] = DP[i+1][j-1]; // } else { // if no chat between i and j // DP[i][j] = 0; // } // } else { // int res1 = 1 + DP[i+1][j]; // int res2 = 1 + DP[i][j-1]; // DP[i][j] = res1 < res2 ? res1: res2; // } // } // } // } // printf("%d\n", DP[0][length-1]); // } void solve() { memset(DP, 0xff, sizeof(DP)); memset(tmp, 0xff, sizeof(tmp)); for (int i = length-1; i >= 0; i--) { memcpy(tmp, DP, sizeof(tmp)); for (int j = i; j <= length-1; j++) { if (i == j) { // only 1 char, no insert DP[j] = 0; } else { // j > i if (str[i] == str[j]) { // both 1st and last char equal if (i+1 < j) { // if some char bertween i and j DP[j] = tmp[j-1]; } else { // if no chat between i and j DP[j] = 0; } } else { int res1 = 1 + DP[j]; int res2 = 1 + DP[j-1]; DP[j] = res1 < res2 ? res1: res2; } } } } printf("%d\n", DP[length-1]); } int main() { while(scanf("%d", &length) != EOF) { scanf("%s", str); solve(); } }
基本经典DP题(从传统方法看),DP[i][j] 表示把输入的字符串S 从i 到j的部分变为回文串所需要的最少插入字符树
那么 DP[i][j]:
case 1: i ==j , 只有一个字符,本身就是回文,不同插入.
case 2: i > j: 没有意义的情况,直接默认-1即可。
case 3: i < j:
subcase 1: 如果 S[i] == S[j] , 那么如果i+1<j(中间还有字符串), 那么就 = DP[i+1][j-1], 否则 = 0
subcase 2: 如果 S[i] != S[j], 那么这时候两个选择: (1) 在j后面插入一个S[i], 那么 = DP[i+1][j] + 1
(2) 在i前面差一个S[j], 那么 =DP[i][j-1] + 1,
两者找最小即可.
一开始用int开的二维数组,直接MLE,改成short过关,尝试了下滚动数组压成一维,发现在这种方法下,不能压缩,
结合上面分析,可以看到 DP[i][j] 依赖 于 DP[i+1][j-1], DP[i+1][j] 和 DP[i][j-1],这就出现了矛盾:
DP[i][j] 依赖于DP[i+1][j-1] 和DP[i][j-1], 如果是滚动一维数组的话,这就说明DP[j] 既依赖于更新前的DP[j-1] 也依赖于更新后的DP[j-1], 在只有一个数组的情况下,是不可能两者兼的, 其实解决应该也是简单的,既然依赖了两层,那么可以搞两个滚动的一维数组A B应该就可以解决这个问题,A和以前一样作用, 每轮i迭代时拷贝一份当前的A到B, 就可以了,B此时保存的就是上一轮的DP值,A可以放心更新.
看到discuss后面还有人说本题实质是求该字符串和自己反向字符串的最长字符串距离,也要好好想想.