题意:给你一个字符串, 求最长的回文子序列, 若答案不唯一, 则输出字典序最小的
分析:
解法1 :
区间dp, dp[i][j]表示字符串s[i]到s[j]构成回文子序列学删除的最小字符数,
dp[i][j] 字符串s[i]到s[j]构成回文子序列许删除的最少字符数
path[i][j] 字符串s[i]到s[j]可构成的最长回文子序列
#include
#include
#include
#include
#include
using namespace std;
string path[1010][1010];
int dp[1010][1010];
char s[1010];
int main() {
while(scanf("%s", s + 1) == 1) {
int n = strlen(s + 1);
for(int i=n; i>=1; i--)
for(int j=i; j<=n; j++) {
if(s[i] == s[j]) {
if(i == j) {
dp[i][j] = 0;
path[i][j] = s[i];
}
else {
dp[i][j] = dp[i+1][j-1];
path[i][j] = s[i] + path[i+1][j-1] + s[j];
}
}
else if(dp[i+1][j] > dp[i][j-1]) {
dp[i][j] = dp[i][j-1] + 1;
path[i][j] = path[i][j-1];
}
else if(dp[i][j-1] > dp[i+1][j]) {
dp[i][j] = dp[i+1][j] + 1;
path[i][j] = path[i+1][j];
}
else {
dp[i][j] = dp[i+1][j] + 1;
path[i][j] = min(path[i][j-1], path[i+1][j]);
}
}
cout << path[1][n] << endl;
}
return 0;
}
解法2:
转化为lcs, 用结构体进行保存,一维只长度, 一维指构成的字符串
#include
#include
#include
#include
#include
using namespace std;
struct node {
int len;
string str;
}dp[1010][1010];
char s1[1010], s2[1010];
int main() {
while(scanf("%s", s1+1) == 1) {
int n = strlen(s1 + 1);
strcpy(s2+1, s1+1);
reverse(s2+1, s2+1+n);
for(int i=0; i<=n; i++)
for(int j=0; j<=n; j++) {
dp[i][j].len = 0;
dp[i][j].str = "";
}
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++) {
if(s1[i] == s2[j]) {
dp[i][j].len = dp[i-1][j-1].len + 1;
dp[i][j].str = dp[i-1][j-1].str + s1[i];
}
else if(dp[i-1][j].len > dp[i][j-1].len) {
dp[i][j].len = dp[i-1][j].len;
dp[i][j].str = dp[i-1][j].str;
}
else if(dp[i][j-1].len > dp[i-1][j].len) {
dp[i][j].len = dp[i][j-1].len;
dp[i][j].str = dp[i][j-1].str;
}
else {
dp[i][j].len = dp[i-1][j].len;
dp[i][j].str = min(dp[i][j-1].str, dp[i-1][j].str);
}
}
string s = dp[n][n].str;
int l = dp[n][n].len;
if(l & 1) {
for(int i=0; i<(l-1)/2; i++)
cout << s[i];
for(int i=(l-1)/2; i>=0; i--)
cout << s[i];
}
else {
for(int i=0; i=0; i--)
cout << s[i];
}
cout << endl;
}
return 0;
}