HDU1513:Palindrome

来源:互联网 发布:mac sed命令应用 编辑:程序博客网 时间:2024/06/05 07:12

点击打开题目链接

Palindrome

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 2437    Accepted Submission(s): 842


Problem Description
A palindrome is a symmetrical string, that is, a string read identically from left to right as well as from right to left. You are to write a program which, given a string, determines the minimal number of characters to be inserted into the string in order to obtain a palindrome. 

As an example, by inserting 2 characters, the string "Ab3bd" can be transformed into a palindrome ("dAb3bAd" or "Adb3bdA"). However, inserting fewer than 2 characters does not produce a palindrome.
 

Input
Your program is to read from standard input. The first line contains one integer: the length of the input string N, 3 <= N <= 5000. The second line contains one string with length N. The string is formed from uppercase letters from 'A' to 'Z', lowercase letters from 'a' to 'z' and digits from '0' to '9'. Uppercase and lowercase letters are to be considered distinct.
 

Output
Your program is to write to standard output. The first line contains one integer, which is the desired minimal number.
 

Sample Input
5Ab3bd
 

Sample Output
2
 

Source
IOI 2000
 

Recommend
linle
 


=====================================题目大意=====================================


通过添加字符将给定的字符串构造成回文字符串,求解至少需要添加多少个字符。


=====================================算法分析=====================================


一、区间动态规划:


    如果用F[L][R](L<=R)表示将给出的字符串中下标介于L与R之间的字符构成的子串构造成回文字符串所需添加字符的最小个数。

    那么所求即为F[0][N-1],而动态转移方程为:

              | F[L+1][R-1]                              (Str[L]==Str[R])

    F[L][R] = |

              | MIN( F[L+1][R] , F[L][R-1] ) + 1         (Str[L]!=Str[R])  

      

二、最长公共子序列:

       

    一开始不是很理解,前往神界请教之后,根据冥王HDS给出的神解整理得出了以下思路。

    减少所需添加字符的个数事实上就是让给出的字符串Str1中的字符尽可能的自我配对而让剩下的字符通过添加字符来配对。

    如果将这些自我配对的字符提取出来按原顺序组成一个字符串Str3。

    那么显然Str3是Str1的子串,而又因为Str3是回文字符串那么它必定也是Str1的逆序字符串Str2的子串。

    所以说Str1中所有的字符自我配对方案Str3都是Str1与Str2的公共子序列。

    那么显然最佳的自我配对方案即Str1与Str2的的最长公共子序列,故而答案即Len(Str1) - MAX{ Len(Str3) }

        

注:由于空间限制,以上任何一种算法都必须使用滚动数组优化DP过程(或者使用short int 来声明记忆化的二维数组)。

    至于时间限制,以上任何一种算法理论上都会超时,幸好是数据太水了。


=======================================代码=======================================


一、区间动态规划。




#include<stdio.h>  #include<string.h>  int N,F[2][5005];    char Str[5005];int MIN(int A,int B) {return A<B?A:B;}int main()  {      while(scanf("%d%s",&N,Str)==2)      {  memset(F,0,sizeof(F));int Roll=0;for(int i=N-2;i>=0;--i){Roll=!Roll;for(int j=i+1;j<=N-1;++j){if(Str[i]==Str[j]){F[Roll][j]=F[!Roll][j-1];}else{F[Roll][j]=MIN(F[!Roll][j],F[Roll][j-1])+1;    }}}printf("%d\n",F[Roll][N-1]);    }      return 0;  }

二、最长公共子序列。



#include<stdio.h>#include<string.h>#define MAX(A,B)  ((A)>(B)?(A):(B))int N,F[2][5005];char Str[5005];int main(){while(scanf("%d%s",&N,Str)==2){memset(F,0,sizeof(F));int Roll=0;for(int i=0;i<N;++i){Roll=!Roll;for(int j=0;j<N;++j){if(Str[i]==Str[N-j-1]) {F[Roll][j+1]=F[!Roll][j]+1;}else{ F[Roll][j+1]=MAX(F[!Roll][j+1],F[Roll][j]);}}}printf("%d\n",N-F[Roll][N]);}return 0;}
原创粉丝点击