之前并没有想过求解 最长回文子序列 的方法,但是自己想想也是没有什么好的办法可以求出 最长回文子序列 来,而最近遇到了一道题目,在经过问题分析,转化之后,其根本的问题就是 最长回文子序列 的求解问题。
==题意:
两只兔子在一个由n个数字组成的环上,一只只能顺时针跳,另一只只能逆时针跳。跳的规则如下:
1、以前跳过了就不要再跳到这个点
2、不能跨过以前跳过的点 比如说以前走过2了,那么这次在1号点的话,就不能到2,3,4…… 如果是顺时针的话
3、每一时刻两只兔子所在的点权值都必须一样
问题解决办法:
转化成找这个环上的 最长回文子序列 问题。则两个兔子可以从某一点出发就可以完成题目要求的跳的过程。
解决代码:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 1005;
int a[maxn];
int d[maxn][maxn];///d[i][j]表示从位置i到位置j这一段中的最长回文子序列;
int main()
{
int n;
while(scanf("%d",&n)!=EOF){
if(n==0) break;
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
memset(d,0,sizeof(d));
for(int i=1;i<=n;i++) d[i][i] = 1;///初始化为1,而非0;
for(int i = n ; i >= 1 ; i--)///i要从大到小枚举,j要从小到大枚举,因为之后的递推会用得到之前得到的值;
///比如:“d[i][j] = d[i+1][j-1]+2;”
{
for(int j = i+1; j <= n ; j++)
{
if(a[i]==a[j])
d[i][j] = d[i+1][j-1]+2;
d[i][j] = max(d[i][j],max(d[i+1][j],d[i][j-1]));
}
}
int ans = 1;
for(int i=1;i<n;i++){///因为这道题是一个环,所以点i上的最长回文子序列应该是两个区间最长回文子序列加起来;
ans = max(ans,d[1][i]+d[i+1][n]);///如果忘了画个圈圈表示一下就明白了;
}
printf("%d\n",ans);
}
return 0;
}