POJ 1159 Palindrome(区间DP/最长公共子序列+滚动数组)

Palindrome

Time Limit: 3000MS   Memory Limit: 65536K
Total Submissions: 56150   Accepted: 19398

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

5
Ab3bd

Sample Output

2

给一个字符串,计算最少加多少个字符能够使字符串变成回文串(即从前往后读与从后往前读一样)。

有2种思路,一种是直接区间DP,dp[j][i]表示[i,j]这个子串要变成回文串需要添加多少个字符,状态转移方程如下:

if(s[i]==s[j])

dp[j][i]=dp[j+1][i-1];

else

dp[j][i]=1+min(min[j+1][i],min[j][i-1])

第二种思路也比较容易想,要将一个字符串变为回文串,那么我们就可以先得到这个字符串的逆序串,然后再求出这两个的最长公共子序列,要添加的字符数就是字符串长度减去最长公共子序列的长度。

另外,这道题还会限制内存。如果定义一个5000*5000的数组会Memory Limit Exceeded。有两种解决方案,一是把数组定义成short型,这样原本的内存会减少很大一部分,大概会在50000kb左右,刚好能够AC;另一种解决方案:因为计算第i行时只需要知道第i-1行,所以可以开一个2*5000的滚动dp数组,这种方法比较推荐,非常节省内存。

/*
LCS+short
Memory: 49688 KB	Time: 1094 MS
Language: G++		Result: Accepted
*/
#include<stack>
#include<queue>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#pragma commment(linker,"/STACK: 102400000 102400000")
#define lson a,b,l,mid,cur<<1
#define rson a,b,mid+1,r,cur<<1|1
using namespace std;
const double eps=1e-6;
const int MAXN=5001;

char s[MAXN],t[MAXN];
int n,ans,tlen;
short int dp[MAXN][MAXN];

int main()
{
#ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
#endif // ONLINE_JUDGE
    while(scanf("%d",&n)!=EOF)
    {
        scanf("%s",s+1);
        for(int i=n;i>=1;i--)
            t[n-i+1]=s[i];
        t[n+1]=0;
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                if(s[i]==t[j])
                    dp[i][j]=dp[i-1][j-1]+1;
                else
                    dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
        printf("%d\n",n-dp[n][n]);
    }
    return 0;
}
/*
DP+short
Memory: 55716 KB	Time: 1454 MS
Language: G++		Result: Accepted
*/
#include<stack>
#include<queue>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#pragma commment(linker,"/STACK: 102400000 102400000")
#define lson a,b,l,mid,cur<<1
#define rson a,b,mid+1,r,cur<<1|1
using namespace std;
const double eps=1e-6;
const int MAXN=5300;

char s[MAXN];
short int n,dp[MAXN][MAXN];

int main()
{
#ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
#endif // ONLINE_JUDGE
    while(scanf("%d",&n)!=EOF)
    {
        scanf("%s",s);
        memset(dp,0,sizeof(dp));
        for(int i=1;i<n;i++)
            for(int j=i-1;j>=0;j--)
            {
                if(s[i]==s[j])
                    dp[j][i]=dp[j+1][i-1];
                else
                    dp[j][i]=(short int)(min(dp[j+1][i],dp[j][i-1])+1);
            }
        printf("%d\n",dp[0][n-1]);
    }
    return 0;
}
/*
LCS+滚动数组
Memory: 728 KB		Time: 735 MS
Language: G++		Result: Accepted
*/
#include<stack>
#include<queue>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#pragma commment(linker,"/STACK: 102400000 102400000")
#define lson a,b,l,mid,cur<<1
#define rson a,b,mid+1,r,cur<<1|1
using namespace std;
const double eps=1e-6;
const int MAXN=5001;

char s[MAXN],t[MAXN];
int n,ans,tlen,dp[2][MAXN];

int main()
{
#ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
#endif // ONLINE_JUDGE
    while(scanf("%d",&n)!=EOF)
    {
        scanf("%s",s+1);
        for(int i=n; i>=1; i--)
            t[n-i+1]=s[i];
        t[n+1]=0;
        memset(dp,0,sizeof(dp));
        int indexs=0;
        for(int i=1; i<=n; i++)
        {
            indexs=!indexs;
            for(int j=1; j<=n; j++)
                if(s[i]==t[j])
                    dp[indexs][j]=dp[!indexs][j-1]+1;
                else
                    dp[indexs][j]=max(dp[!indexs][j],dp[indexs][j-1]);
        }
        printf("%d\n",n-dp[indexs][n]);
    }
    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-04 19:17:57

POJ 1159 Palindrome(区间DP/最长公共子序列+滚动数组)的相关文章

POJ1159——Palindrome(最长公共子序列+滚动数组)

Palindrome DescriptionA 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 inser

POJ 2250 Compromise (DP,最长公共子序列)

Compromise Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 6440 Accepted: 2882 Special Judge Description In a few months the European Currency Union will become a reality. However, to join the club, the Maastricht criteria must be fulfille

hdu 1159 Common Subsequence(dp 最长公共子序列问题LCS)

最长公共子序列问题(LCS,Longerst Common Subsequence). s1s2……si+1和t1t2……tj+1的公共子序列可能是: ①当si+1=tj+1时,在s1s2……si+1和t1t2……tj+1的公共子序列末尾追加一个. ②s1s2……si+1和t1t2……tj的公共子序列 ③s1s2……si和t1t2……tj+1的公共子序列 所以易得到递推关系dp[i+1][j+1]=  max{ dp[i][j]+1 , dp[i][j+1] , dp[i+1][j]) }  

hdu 1159 Common Subsequence(最长公共子序列,DP)

题意: 两个字符串,判断最长公共子序列的长度. 思路: 直接看代码,,注意边界处理 代码: char s1[505], s2[505]; int dp[505][505]; int main(){ while(scanf("%s%s",s1,s2)!=EOF){ int l1=strlen(s1); int l2=strlen(s2); mem(dp,0); dp[0][0]=((s1[0]==s2[0])?1:0); rep(i,1,l1-1) if(s1[i]==s2[0]) dp

poj1159--Palindrome(dp:最长公共子序列变形 + 滚动数组)

Palindrome Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 53414   Accepted: 18449 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

POJ 1458 - Common Subsequence(最长公共子序列) 题解

此文为博主原创题解,转载时请通知博主,并把原文链接放在正文醒目位置. 题目链接:http://poj.org/problem?id=1458 题目大意: 有若干组数据,每组给出两个字符串(中间用任意数量的空格间隔),输出这两个字符串最长公共子序列的长度.每次输出后换行. 分析: 动态规划求LCS,f[i][j]表示第一个字符串匹配到第i位,第二个字符串匹配到第j位时最长公共子序列的长度. 转移方程:当a[i] = b[i]时,f[i][j] = f[i-1][j-1]+1,其他情况时f[i][j

POJ 1458 Common Subsequence 【最长公共子序列】

解题思路:先注意到序列和串的区别,序列不需要连续,而串是需要连续的,先由样例abcfbc         abfcab画一个表格分析,用dp[i][j]储存当比较到s1[i],s2[j]时最长公共子序列的长度 a    b    f    c    a    b 0    0    0    0    0   0    0 a  0    1     1    1    1   1    1 b  0    1     2    2    2   2    2 c  0    1     2  

hdu 1159 Common Subsequence(最长公共子序列)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1159 Common Subsequence Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 37551    Accepted Submission(s): 17206 Problem Description A subsequence of

hdu1159 dp(最长公共子序列)

题意:给两个字符串,求这两个字符串的最长公共子序列的长度 因为之前集训的时候做过,所以现在即使会做也并不是什么稀奇的事,依旧为了自己的浅薄感到羞愧啊``` 解法就是通过两个字符串的每个字符互相比较,根据比较情况相同与否确定递推关系: dp [ i + 1 ] [ j + 1 ] 表示匹配到 a 字符串的第 i 个字符和 b 字符串的第 j 个字符时的最大匹配数,由于读字符串的时候我是从下标 0 读起的,但我需要用 dp [ 0 ] ,所以就都是加了一,否则也可以读入的时候直接从 a + 1 和