POJ - 1159 Palindrome(回文串&LCS最长公共子序列&滚动数组)

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
5
Ab3bd
Sample Output
2

题意:给出一个长度为n的串,判断这个串至少还需加入几个字符能变成一个回文串。

题解:LCS最长公共子序列模板题,将原串倒过来,和原串求一下LCS,公共部分即不用增加字符的一部分回文串,剩余部分即已经存在,那么就要在另一边的相应位置插入这些不回文的字符,因此是原串长度减去LCS长度即结果。

因为有5000的长度字符串,开5000*5000的dp数组会超内存,鉴于我们存储的最长回文串值不会超过5000,而能存下1e5值的short int是绰绰有余。可以偷懒直接改成short int能勉强过。
而这题优雅的做法应该是用滚动数组来写,代码中随意取一个坐标的值,可以是坐标可以使纵坐标,对其取模2即可。因为最多只是用前一个字符的值。

滚动数组代码:

#include<stdio.h>///最长公共子序列/滚动数组
#include<string.h>
#include<algorithm>
using namespace std;
int vis[10][5009],t;
char x[5005];
char y[5004];
int main()
{
    int lx;
    while(scanf("%d",&lx)!=EOF)
    {
        scanf("%s",x+1);
        int ly=0;
        for(int i=lx; i>=1; i--) y[++ly]=x[i];
//        printf("%s  \n%s\n",x+1,y+1);
        for(int i=1; i<=lx; i++)vis[i%2][0]=0;
        for(int i=1; i<=ly; i++)vis[0][i]=0;
        vis[0][0]=0;
        for(int i=1; i<=lx; i++)
        {
            for(int j=1; j<=ly; j++)
            {
                vis[i%2][j]=0;
                if(x[i]!=y[j])
                {
                    vis[i%2][j]=vis[(i-1)%2][j-1];
                    vis[i%2][j]=max(vis[(i-1)%2][j],max(vis[i%2][j],vis[i%2][j-1]));
                }
                else vis[i%2][j]=vis[(i-1)%2][j-1]+1;
            }
        }
        printf("%d\n",ly-vis[lx%2][ly]);
    }
    return 0;
}

short int代码:

#include<stdio.h>///最长公共子序列 /short int
#include<string.h>
#include<algorithm>
using namespace std;
short int vis[5008][5009],t;
char x[5005];
char y[5004];
int main()
{
    int lx;
    while(scanf("%d",&lx)!=EOF)
    {
        scanf("%s",x+1);
        int ly=0;
        for(int i=lx; i>=1; i--) y[++ly]=x[i];
//        printf("%s  \n%s\n",x+1,y+1);
        for(int i=1; i<=lx; i++)vis[i][0]=0;
        for(int i=1; i<=ly; i++)vis[0][i]=0;
        vis[0][0]=0;
        for(int i=1; i<=lx; i++)
        {
            for(int j=1; j<=ly; j++)
            {
                vis[i][j]=0;
                if(x[i]!=y[j])
                {
                    vis[i][j]=vis[i-1][j-1];
                    vis[i][j]=max(vis[i-1][j],max(vis[i][j],vis[i][j-1]));
                }
                else vis[i][j]=vis[i-1][j-1]+1;
            }
        }
        printf("%d\n",ly-vis[lx][ly]);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/kuronekonano/article/details/80247731