题目大意:给定一个字符串,求最少插入多少个字符,可将其变成一个回文串。
思路:所谓回文串,即原字符串与翻转之后的字符串完全一致。设题目中给定的字符串为stra, 将其翻转之后为字符串strb, 题目的意思为最少插入多少个字符使得stra与strb互为回文串 。如果反过来思考的话,问题可以转化为:若stra与strb拥有公共的字符串越多,则仅需要插入哪些不同的字符即可满足条件,于是问题进一步转化为寻求stra与strb的最长公共字串问题(LCS)。
#include <stdio.h>
#include <assert.h>
#include <string.h>
#define max(a,b) (((a) > (b)) ? (a) : (b))
int N;
char str[5001];
char rev[5001];
unsigned short int dp[5001][5001];
void reverse_string(char* str, char* rev)
{
assert(str);
assert(rev);
int i,len;
len = strlen(str);
for(i=0; i<len; i++){
rev[i] = str[len-i-1];
}
rev[i] = '\0';
return;
}
unsigned short int LCS(char* str, char* rev)
{
int i,j,lena,lenb;
lena = strlen(str);
lenb = strlen(rev);
for(i=1; i<=lena; i++){
dp[i][0] = 0;
}
for(j=1; j<=lenb; j++){
dp[0][j] = 0;
}
for(i=1; i<=lena; i++){
for(j=1; j<=lenb; j++){
if(str[i-1] == rev[j-1]) dp[i][j] = dp[i-1][j-1] + 1;
else dp[i][j] = max(dp[i][j-1],dp[i-1][j]);
}
}
int max_len = 0;
for(i=0; i<=lena; i++)
for(j=0; j<=lenb; j++)
if(max_len < dp[i][j]) max_len = dp[i][j];
return max_len;
}
int main()
{
while(scanf("%d",&N) == 1){
assert(N>=3 && N<=5000);
scanf("%s",str);
reverse_string(str,rev);
printf("%d\n",strlen(str)-LCS(str,rev));
}
return 0;
}