题目链接。
分析:
感叹算法的力量。
方法一:
设 dp[i][j] 为字符串 s, 从 i 到 j 需要添加的最少字符数。
那么如果 s[i] == s[j], dp[i][j] = dp[i+1][j-1]. 如果 s[i] != s[j], dp[i][j] = min(dp[i+1][j], dp[i][j-1]) + 1.
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <map> using namespace std; const int maxn = 5000; short dp[maxn][maxn]; char s[maxn]; int d(int i, int j) { if(i >= j) return 0; else if(dp[i][j] != -1) return dp[i][j]; else if(s[i] != s[j]) return (dp[i][j] = min(d(i+1, j), d(i, j-1)) + 1); else return dp[i][j] = d(i+1, j-1); } int main(){ // freopen("my.txt", "r", stdin); int n; while(scanf("%d", &n) == 1) { memset(dp, -1, sizeof(dp)); scanf("%s", s); d(0, n-1); printf("%d\n", dp[0][n-1]); } return 0; }
方法二:
LCS + 滚动数组.
设原序列S的逆序列为S',
最少需要补充的字母数 = 原序列S的长度 — S和S'的最长公共子串长度
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <map> using namespace std; const int maxn = 5000+10; int dp[2][maxn]; char s1[maxn], s2[maxn]; int main(){ int n; while(scanf("%d", &n) == 1) { scanf("%s", s1); memset(dp[0], 0, sizeof(dp[0])); for(int i=0; i<n; i++) { s2[n-i-1] = s1[i]; } s2[n] = '\0'; for(int i=1; i<=n; i++) { for(int j=1; j<=n; j++) { if(s1[i-1] == s2[j-1]) dp[i%2][j] = dp[(i-1)%2][j-1] + 1; else dp[i%2][j] = max(dp[(i-1)%2][j], dp[i%2][j-1]); } } printf("%d\n", n-dp[n%2][n]); } return 0; }