【动态规划】【poj 1159】palindrome

问题

给定一个长度为n(<=5000)的字符串,求最少添加几个字符使之变成回文串

分析

设原序列S的逆序列为S'则这道题目的关键在于,

最少需要补充的字母数= 原序列S的长度 SS'的最长公共子串长度

设 S 为原字符串,RS=reverse(S)即S反转后的字符串,LCS(S,RS)为S与RS的最长公共子序列,len(S)为S的长度。令S={a1~an},则RS={an~a1},S-LCS(S,RS)={b1~bn},这里的集合都是有序、元素可重复的;bi∈S,RS;且i≠j时,bi≠bj,否则有bi∈LCS(S,RS);同时LCS(S,RS)一定是回文,因为其是在S的正序与逆序下同时出现的子序列。由上,只需添加字符将S-LCS(S,RS)变成回文即可,设size=len(S-LCS(S,RS));因为其元素各不相同,此时有两种方案使之成为回文:1.添加size-1个字符,例如:c1c2c3 --> c1c2c3c2c1;2.添加size个;对于第一种,c3肯定是在回文中的中间位置,也必须是在LCS(S,RS)的中间位置,即c3∈LCS(S,RS),所以排除这种情况。于是最少需添加size个字符,即min=len(S)-len(S,RS)。

这个证明需要自己思考一下。

这道题由于空间需求很大,所以考虑用滚动数组优化。

由于i之和i中已更新的和i-1有关,所以只需2*5000就能解决问题,但是会使算法的时间复杂度接近n3,以时间换空间,所谓的求余滚动效率并不高,因为mod运算非常之慢。

code

program liukeke;
var
  f:array[0..1,0..5001] of longint;
  n,i,j:longint;
  s1,s2:ansistring;

function max(a,b:longint):longint;
begin
  if a>b then exit(a);
  exit(b);
end;


begin
  readln(n);
  readln(s1);
  for i:=1 to length(s1) do
    s2:=s1[i]+s2;
  for i:=1 to length(s1) do
  begin
    for j:=1 to length(s2) do
      if s1[i]=s2[j] then
	    f[1,j]:=f[0,j-1]+1
	  else
	    f[1,j]:=max(f[0,j],f[1,j-1]);
    f[0]:=f[1];
  end;
  writeln(length(s1)-f[1,length(s2)]);
end.

反思

要看清题目,不要一味套用经典算法,通过分析使之和经典算法建立联系。

考虑优化

posted @ 2011-06-27 17:30  liukee  阅读(421)  评论(0编辑  收藏  举报