POJ1159 Palindrome

来源:互联网 发布:数据恢复精灵绿色版 编辑:程序博客网 时间:2024/05/16 00:40

题目:http://acm.pku.edu.cn/JudgeOnline/problem?id=1159

思路:求字符串和它的反序字符串的最长子序列长度(LCS),再用字符串长度去剪掉子序列长度。

            求LCS方法:DP。

 

****************************************以下为引用******************************************

LCS问题

LCS(最长公共子序列)问题可以简单地描述如下:

一个给定序列的子序列是在该序列中删去若干元素后得到的序列。给定两个序列X和Y,当另一序列Z既是X的子序列又是Y的子序列时,称Z是序列X和Y的公共子序列。例如,若X={A,B,C,B,D,B,A},Y={B,D,C,A,B,A},则序列{B,C,A}是X和Y的一个公共子序列,但它不是X和Y的一个最长公共子序列。序列{B,C,B,A}也是X和Y的一个公共子序列,它的长度为4,而且它是X和Y的一个最长公共子序列,因为X和Y没有长度大于4的公共子序列。

最长公共子序列问题就是给定两个序列X={x1,x2,...xm}和Y={y1,y2,...yn},找出X和Y的一个最长公共子序列。对于这个问题比较容易想到的算法是穷举,对X的所有子序列,检查它是否也是Y的子序列,从而确定它是否为X和Y的公共子序列,并且在检查过程中记录最长的公共子序列。X的所有子序列都检查过后即可求出X和Y的最长公共子序列。X的每个子序列相应于下标集{1,2,...,m}的一个子集。因此,共有2^m个不同子序列,从而穷举搜索法需要指数时间。

事实上,最长公共子序列问题具有最优子结构性质:

设序列X={x1,x2,...,xm}和Y={y1,y2,...,yn}的一个最长公共子序列为Z={z1,z2,...,zk},则

1. 若xm=yn,则zk=xm=yn,且Zk-1是Xm-1和Yn-1的最长公共子序列。
2. 若xm!=yn且zk!=xm,则Z是Xm-1和Y的最长公共子序列。
3. 若xm!=yn切zk!=yn,则Z是X和Yn-1的最长公共子序列。

通过以上的结论,我们观察到——两个序列的最长公共子序列包含了这两个序列的前缀的最长公共子序列,这为我们将算法的时间复杂度降低到多项式级别埋下了伏笔,因为这两个序列的不同的前缀组合只有O(mn)个。并且,根据以上结论,我们可以得出计算Xi和Yj的最长公共子序列的长度c[i][j]的公式:

当i=0或j=0时,c[i][j]=0。当i,j>0且xi=yj时,c[i][j]=c[i-1][j-1]+1。当当i,j>0且xi!=yj时,c[i][j]=max{c[i][j-1],c[i-1][j]}。

这样一来,解决这个问题就比较容易了,通过建立递推结构,可以得出下列算法:

  1. for (i=1;i<=m;++m) 
  2.   c[i][0]=0;
  3. for (i=1;i<=n;++i) 
  4.   c[0][i]=0;
  5. for (i=1;i<=m;++i)
  6.  { 
  7.   for (j=1;j<=n;++j)
  8.   {
  9.    if (x[i]==y[j])
  10.     c[i][j]=c[i-1][j-1]+1;
  11.    else if (c[i-1][j]>=c[i][j-1])
  12.     c[i][j]=c[i-1][j];
  13.    else
  14.     c[i][j]=c[i][j-1];
  15.   }
  16.  }

X和Y的最长公共子序列的长度就存于c[m][n]中,欲求出具体的子序列,则可通过数组的值用O(m+n)的时间回推,具体的方法不再赘述。

 

****************************************以上为引用******************************************

 

本题代码:

 

  1. import java.io.BufferedReader;
  2. import java.io.IOException;
  3. import java.io.InputStreamReader;
  4. public class Main {
  5.     public static void main(String[] args) throws NumberFormatException,
  6.             IOException {
  7.         BufferedReader read = new BufferedReader(new InputStreamReader(
  8.                 System.in));
  9.         int len = Integer.parseInt(read.readLine());
  10.         String s = read.readLine();
  11.         StringBuilder b = new StringBuilder(s);
  12.         b.reverse();
  13.         char[] x = s.toCharArray();
  14.         char[] y = b.toString().toCharArray();
  15.         int[] c1 = new int[len + 1];
  16.         int[] c2 = new int[len + 1];
  17.         int max = 0;
  18.         for (int i = 1; i < len + 1; i++) {
  19.             for (int j = 1; j < len + 1; j++) {
  20.                 if (x[i - 1] == y[j - 1]) {
  21.                     c2[j] = c1[j - 1] + 1;
  22.                 } else {
  23.                     c2[j] = Math.max(c2[j - 1], c1[j]);
  24.                 }
  25.                 max = Math.max(max, c2[j]);
  26.             }
  27.             c1 = c2.clone();
  28.         }
  29.         System.out.println(len - max);
  30.     }
  31. }