UVa11404 - Palindromic Subsequence(区间DP+打印路径)

题目大意

给定一个字符串,要求你删除尽量少的字符,使得原字符串变为最长回文串,并把回文串输出,如果答案有多种,则输出字典序最小的

题解

有两种解法,第一种是把字符串逆序,然后求两个字符串的LCS,并记录LCS,长度就等于最长回文串的长度,不过求出来的LCS不一定是回文串,例如下面这个例子

        s  = 1 5 2 4 3 3 2 4 5 1
reverse(s) = 1 5 4 2 3 3 4 2 5 1
       LCS = 1 5 2   3 3   4 5 1
所以我们只需要LCS的前半段即可

代码:

#include <cstdio>
#include <algorithm>
#include <string>
#include <iostream>
#include <utility>
using namespace std;
#define MAXN 1005
string a,b;
pair<int,string>dp[MAXN][MAXN];
int main()
{
    while(cin>>a)
    {
        int len=a.length();
        b=a;
        reverse(b.begin(),b.end());
        for(int i=0;i<len;i++)
        {
            dp[0][i].first=0,dp[0][i].second="";
            dp[i][0].first=0,dp[i][0].second="";
        }
        for(int i=0;i<len;i++)
            for (int j=0;j<len;j++)
                if(a[i]==b[j])
                {
                    dp[i+1][j+1].first=dp[i][j].first+1;
                    dp[i+1][j+1].second=dp[i][j].second+a[i];
                }
                else
                {
                    if(dp[i+1][j].first>dp[i][j+1].first)
                    {
                        dp[i+1][j+1].first=dp[i+1][j].first;
                        dp[i+1][j+1].second=dp[i+1][j].second;
                    }
                    else
                        if(dp[i+1][j].first==dp[i][j+1].first)
                        {
                            dp[i+1][j+1].first=dp[i][j+1].first;
                            dp[i+1][j+1].second=min(dp[i][j+1].second,dp[i+1][j].second);
                        }
                        else
                        {
                            dp[i+1][j+1].first=dp[i][j+1].first;
                            dp[i+1][j+1].second=dp[i][j+1].second;
                        }
                }
                int lens=dp[len][len].first;
                string s=dp[len][len].second;
                if(lens&1)
                {
                    int t=lens/2;
                    for(int i=0;i<=t;i++)
                        cout<<s[i];
                    for(int i=t-1;i>=0;i--)
                        cout<<s[i];
                    cout<<endl;
                }
                else
                {
                    int t=lens/2;
                    for(int i=0;i<t;i++)
                        cout<<s[i];
                    for(int i=t-1;i>=0;i--)
                        cout<<s[i];
                    cout<<endl;
                }
    }
    return 0;
}

第二种方法和POJ1159一样,不过是多了个路径而已

代码:

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <string>
using namespace std;
#define MAXN 1005
string s;
int dp[MAXN][MAXN];
string path[MAXN][MAXN];
int main()
{
    int n;
    while(cin>>s)
    {
        memset(dp,0,sizeof(dp));
        int n=s.length();
        for(int i=n-1; i>=0; i--)
            for(int j=i; j<n; j++)
                if(s[i]==s[j])
                {
                    dp[i][j]=dp[i+1][j-1];
                    if(i!=j)path[i][j]=s[i]+path[i+1][j-1]+s[j];
                    else
                        path[i][j]=s[i];
                }
                else
                {
                    if(dp[i+1][j]<dp[i][j-1])
                    {
                        dp[i][j]=dp[i+1][j]+1;
                        path[i][j]=path[i+1][j];
                    }
                    else
                        if(dp[i+1][j]==dp[i][j-1])
                        {               
                            dp[i][j]=dp[i+1][j]+1;
                            path[i][j]=min(path[i+1][j],path[i][j-1]);
                        }
                        else
                        {
                            dp[i][j]=dp[i][j-1]+1;
                            path[i][j]=path[i][j-1]; 
                        }
                }
                cout<<path[0][n-1]<<endl;
    }
    return 0;
}

posted on 2013-08-20 16:40  仗剑奔走天涯  阅读(315)  评论(0编辑  收藏  举报

导航