Palindrome poj 1159 c++

来源:互联网 发布:英文起名软件 编辑:程序博客网 时间:2024/04/28 21:33

Palindrome

Time Limit: 3000MS Memory Limit: 65536KTotal Submissions: 52560 Accepted: 18119

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

 

 

 

 

题意:回文词是一种对称的字符串。把任意给定一个字符串用最少的步骤数,通过插入若干字符,都可以变成回文词。比如 “Ab3bd”插入2个字符后可以变成回文词“dAb3bAd”或“Adb3bdA”,但是插入少于2个的字符无法变成回文词。

 

方法一:倒序后比较,求出最长子序列,然后在用长度减去最长子序列的值即为改变的值;

代码如下:

 

#include<cstdio>#include<cstring>#define max(a,b) (a>b?a:b)char str[5050],str1[5050];short c[5050][5050];int main(){    int i,j,n;    while(scanf("%d",&n)!=EOF)    {        getchar();        memset(c,0,sizeof(c));        memset(str,0,sizeof(str));        memset(str1,0,sizeof(str1));        for(i=1;i<=n;i++)             scanf("%c",&str[i]);        for(j=1,i=n;i>0;i--)            str1[j++]=str[i];        for(i=1;i<=n;i++)            for(j=1;j<=n;j++)        {            if(i==0||j==0)                  c[i][j]= 0;            else if(str[i]==str1[j])                    c[i][j]=c[i-1][j-1]+1;            else if(str[i]!=str1[j])                  c[i][j]=max(c[i][j-1],c[i-1][j]) ;             }         printf("%d\n",n-c[n][n]);        }    return 0;}


 

 

方法二:

c(i,j)表示将子串aia(i+1)aj变成回文词的最小添加字符数。则这此问题就是要求c(1,n)

先来看看求c(1,10),
一。如果a1= a10则c(1,10) =c(2,9);
二。如果a1!= a10则将a1…a10变成回文词无非只有两种情况:
1.先将 a1…a9变成回文词,再在两头加上a10;
2.先将 a2…a10变成回文词,再在两头加上a1;
即c(1,10) =c(1,9)+1或c(1,10) =c(2,10)+1.
综合一和二,则变成了求三个c(1,9),c(2,10),c(2,9),如此类推:求c(1,8),c(2,9),c(2,8) ;c(2,9),c(3,10),c(3,9) ;c(2,8),c(3,9),c(3,8).。。。。。

c(i,j)满足如下递推关系:

 

代码如下:

 

#include <iostream>#include <cstdio>#include <cstring>using namespace std;short dp[5050][5050];//注意用short类型,不然会超空间;char str[5050];int main(){    int n,i,j,k;    memset(dp,0,sizeof(dp));    memset(str,0,sizeof(str));    while(scanf("%d",&n)!=EOF)    {        scanf("%s",str+1);        //getchar();        for(i=1;i<n;i++)        {            for(k=1;i+k<=n;k++)            {                j=i+k;                if(str[k]==str[j])                {                    dp[k][j]=dp[k+1][j-1];                }                else                 {                    dp[k][j]=min(dp[k][j-1]+1,dp[k+1][j]+1);                }            }        }        printf("%d\n",dp[1][n]);    }    return 0;}


 

 

 

0 0
原创粉丝点击