题意: 求最少增加几个字符使得给定的字符串形成回文串;
分析:
最少添加字符个数 = 字符串长度 - 原串与逆序串的最大公共子序列长度 (注意是公共子序列, 不是公共子串, 二者有区分)
code:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
const int maxn = 5050;
char c[maxn];
int dp[2][maxn];
int n;
int LCS(char a[]){//求最长公共子序列
memset(dp, 0, sizeof(dp));
int e=1;
for(int i=n; i>=1; i--){//逆序串
for(int j=1; j<=n; j++){//原串
if(a[i-1] == a[j-1]){
dp[e][j] = dp[!e][j-1]+1;
} else {
dp[e][j] = (dp[!e][j] > dp[e][j-1])?dp[!e][j]:dp[e][j-1];
}
}
e=!e;
}
return dp[!e][n];
}
int main(){
//freopen("in.txt","r",stdin);
scanf("%d", &n);
scanf("%s", c);
//printf("%s\n", rc);
printf("%d\n", n-LCS(c));
return 0;
}
附上最长公共子串模版: (公共子串要求连续, 公共子序列不要求连续)
int LCS(char a[], char b[]){//求最长公共子串
int len1 = strlen(a);
int len2 = strlen(b);
int MAX = 0;
int i, j, k, cnt=0;
for(i=0; i<len2; i++){
memset(num, 0, sizeof(num));
int p = 0; // a字符串
int q = i; // b字符串
while(p<len1 && q<len2){
++cnt;
if(a[p]==b[q]){
num[cnt] = num[cnt-1]+1;
MAX = max(MAX, num[cnt]);
}
p++;
q++;
}
}
cnt=0;
for(i=1; i<len1; i++){
memset(num, 0, sizeof(num));
int p = i; // a字符串
int q = 0; // b字符串
while(p<len1 && q<len2){
++cnt;
if(a[p]==b[q]){
num[cnt] = num[cnt-1]+1;
MAX = max(MAX, num[cnt]);
}
p++;
q++;
}
}
return MAX;
}