题目:http://acm.hust.edu.cn/vjudge/contest/129795#problem/L
题意:
给定一个由小写字母组成的字符串,删除其中的0个或者多个字符,使得剩下的字母(顺序不变)组成一个尽量长的回文串,如果有多解,输出字典序最小的解
思路:
很容易想到的一个做法就是将字符串翻转,然后求正串和反串的最长公共子序列,因为题目要求输出这个序列(字典序最小),用stirng保存一下即可。
这篇博客有详解:http://blog.youkuaiyun.com/shuangde800/article/details/9898675
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
typedef long long ll;
const int INF = 1e9 + 9;
const int N = 1e3+ 9;
char a[N],b[N];
struct Item {
int len;
string str;
};
Item d[N][N];
int main() {
freopen ("f.txt","r",stdin);
int n,T,t,x;
int cas=0;
while (~scanf ("%s",&a) ) {
int n=strlen (a);
for (int i=0; i<n; i++) b[i]=a[n-i-1];
for (int i=0; i<=n; i++)
for (int j=0; j<=n; j++)
d[i][j].len=0,d[i][j].str="";
for (int i=0; i<n; i++) {
for (int j=0; j<n; j++)
if (a[i]==b[j]) {
d[i+1][j+1].len=d[i][j].len+1;
d[i+1][j+1].str=d[i][j].str+a[i];
} else {
if (d[i+1][j].len>d[i][j+1].len) d[i+1][j+1]=d[i+1][j];
else if (d[i+1][j].len<d[i][j+1].len) d[i+1][j+1]=d[i][j+1];
else if (d[i+1][j].str<d[i][j+1].str) d[i+1][j+1]=d[i+1][j];
else d[i+1][j+1]=d[i][j+1];
}
}
int maxn=d[n][n].len;
string ans=d[n][n].str;
if (maxn&1) {
for (int i=0; i<maxn/2; i++) printf ("%c",ans[i]);
for (int i=maxn/2; i>=0; i--) printf ("%c",ans[i]);
} else {
for (int i=0; i<maxn/2; i++) printf ("%c",ans[i]);
for (int i=maxn/2-1; i>=0; i--) printf ("%c",ans[i]);
}
printf ("\n");
}
return 0;
}
这题其实是LPS(Longest Palindromic Subsequence)问题,类似于LCS问题也可以设计个相似的dp状态:
dp[i][j]表示子串s[i…j]之间可以构成的LPS个数,
那么dp转移方程就是:
if(s[i]==s[j])d[i][j]=d[i+1][j-1]+2;
else d[i][j]=max(d[i+1][j],d[i][j-1]);
转移的时候如果直接枚举i,j,肯定会超时。所以划分区间,区间从小到大转移一下就好。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
typedef long long ll;
const int INF = 1e9 + 9;
const int N = 1e3+ 9;
char s[N];
string ans[N][N];
int d[N][N];
void LPS()
{
int n=strlen(s+1);
memset(d,0,sizeof(d));
for(int i=1;i<=n;i++)d[i][i]=1;
for(int i=1;i<=n;i++)ans[i][i]=s[i];
for(int L=2;L<=n;L++){
for(int i=1;i+L-1<=n;i++){
int j=i+L-1;
if(s[i]==s[j]){
if(L==2){
d[i][j]=2;
ans[i][j]=ans[i][i]+ans[j][j];
continue;
}
d[i][j]=d[i+1][j-1]+2;
ans[i][j]=s[i]+ans[i+1][j-1]+s[j];
}
else if(d[i+1][j]>d[i][j-1]){
d[i][j]=d[i+1][j];
ans[i][j]=ans[i+1][j];
}
else if(d[i+1][j]<d[i][j-1]){
d[i][j]=d[i][j-1];
ans[i][j]=ans[i][j-1];
}
else{
d[i][j]=d[i+1][j];
ans[i][j]=min(ans[i+1][j],ans[i][j-1]);
}
}
}
cout<<ans[1][n]<<endl;
}
int main() {
//freopen ("f.txt","r",stdin);
while (~scanf ("%s",s+1) ) {
LPS();
}
return 0;
}
/*
SampleInput
aabbaabb
computer
abzla
samhita
SampleOutput
aabbaa
c
aba
aha
*/