地址:http://poj.org/problem?id=1159
题目需求:
给你一个字符串,求最少添加多少字符可以使之构成回文串。
题目解析:
简单做法是直接对它和它的逆序串求最长公共子序列长度len。n-len即为所求。(n为原串长度)
即 : 最少补充的字母数 = 原序列的长度 — 原串和逆序的最长公共子串长度 , 如果最长公共子串长度==原序列长度,则是回文,反之须补充的数目为n-lcs;
这样做的原因如下:
要求最少添加几个字符,我们可以先从原串中找到一个最长回文串,然后对于原串中不属于这个回文串的字符,在它关于回文串中心的对称位置添加一个相同字符即可。那么需要添加的字符数量即为n-最长回文串长度。
最长回文串可以看作是原串中前面和后面字符的一种匹配(每个后面的字符在前面找到一个符合位置要求的与它相同的字符)。这种的回文匹配和原串与逆序串的公共子序列是一一对应的(一个回文匹配对应一个公共子序列,反之亦然),而且两者所涉及到的原串中的字符数量是相等的,也就是最长公共子序列对应最长回文串。原因陈述完毕。
代码:
#include <iostream> #include <stdio.h> #include <string.h> #include <algorithm> #include <queue> #include <math.h> #define inf 0x3f3f3f3f typedef int ll; #define N 1010 using namespace std; char a[5010],b[5010]; short int c[5010][5010]; int main() { int n; while(scanf("%d",&n)!=EOF) { scanf("%s",a); for(int i=n-1; i>=0; i--) b[n-1-i]=a[i]; for(int i=0; i<n; i++) { c[i][0]=0; c[0][i]=0; } for(int i=1; i<=n; i++) { for(int j=1; j<=n; j++) { if(a[i-1]==b[j-1]) { c[i][j]=c[i-1][j-1]+1; } else { c[i][j]=max(c[i-1][j],c[i][j-1]); } } } printf("%d ",n-c[n][n]); } return 0; }