(环状区间dp)hdu 4745 Two Rabbits

题目
hdu4745

题意:
输出环状数组的子序列(可以不连续)回文串的最长长度

思路:
把数组拉长一倍,
在区间[ i ,j ]内:
如果a [ i ] = a [ j ],则dp [ i ] [ j ] = dp [ i + 1 ] [ j - 1 ] + 2
如果a [ i ] != a [ j ],则dp [ i ] [ j ] = max ( dp [ i + 1 ] [ j ], dp [ i ] [ j - 1 ] )

有一种特殊情况,举个例子:环状数组是1,2,把数组拉长一倍是1,2,1,2,那么dp [ 1 ] [ 2 ] = 1,dp [ 2 ] [ 3 ] = 1,但是答案是2,因为Tom跳的顺序是1,2,Jerry跳的顺序也是1,2,所有答案应该是max ( dp [ i ] [ i + n - 1 ], dp [ i ] [ i + n - 2 ] + 1 )

代码

#include <iostream>
#include <algorithm>
#include <cstring>
#define DEBUG freopen("_in.txt", "r", stdin); freopen("_out1.txt", "w", stdout);
using namespace std;
const int MAXN = 2010;
int a[MAXN], dp[MAXN][MAXN];
void solve(int n){
    
    
	for (int i = 1; i <= n; i++)
		scanf("%d", &a[i]);
	for (int i = 1; i <= n; i++)  //拉长1倍
		a[i+n] = a[i];
	n <<= 1;
	for (int i = 1; i <= n; i++)
		dp[i][i] = 1;
	for (int len = 1; len < n; len++)
		for (int i = 1; i <= n - len; i++){
    
    
			int j = i + len;
			if (a[i] == a[j])
				dp[i][j] = dp[i+1][j-1] + 2;
			else
				dp[i][j] = max(dp[i+1][j], dp[i][j-1]);
		}
	n >>= 1;  //缩回原来长度
	int ans = 0;
	for (int i = 1; i <= n; i++)
		ans = max(ans, max(dp[i][i+n-1], dp[i][i+n-2] + 1));
	printf("%d\n", ans);
}
int main(){
    
    
	int n;
	while (~scanf("%d", &n) && n != 0) 
		solve(n);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/ymxyld/article/details/113799964