1. 程式人生 > >1159 Palindrome(迴文串&LCS最長公共子序列&滾動陣列)

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;
}