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

时间:2023-03-10 05:47:01
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;
}