题意:给你一个字符串, 求最长的回文子序列, 若答案不唯一, 则输出字典序最小的
分析:
解法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; }