HDU-4745-Two Rabbits
这一道题是区间dp.最长回文子序列。
题目大意:有两只兔子。一个只往顺时针方向跳。一个只往逆时针方向跳。这两只兔子每次跳的石头的重量必须相同。
所以很明显啦~有关于回文串的
当初思考的时候想把前面n-1个数直接放在n的后面。。然而。。出现了bug。这个求的区间dp是连续的。但是题目要求的可以不连续。。呃。。
这样思考
我们可以获得两个回文串。然后把这两个回文串组成环。
也是一个回文串。emmm这里可以举例子。
比如样例1 1 2 1
1是一个回文串
1 2 1是一个回文串
他们两个组成的环也是回文串。
所以我们可以通过这种方法求解。
那么问题又来了?这怎么知道是最长的
这个比较好解决
我们在长度为n的序列中跑一遍加起来最长的回文序列长度就行。注意不要重复。因为题目中要求不能踩踩过的石头。
所以dp[i][j]表示i~j的范围内的最长的回文串的长度。
状态转移方程:
也有两种状态。
当s[i] == s[i + len]时
s[i][i + len] = max(s[i][i + len], s[i + 1][i + len - 1] + 2);
当s[i] != s[i + len]时
s[i][i + len] = max(s[i + 1][i + len], s[i][i + len - 1]);
这个好理解。
比较i+1~i+len是否时回文串或者i ~i + len-1是否是回文串。
初始化:
dp[i][i] = 1;代表字符本身也是回文串。
代码部分:
#include <bits/stdc++.h>
#define mst(a, n) memset(a, n, sizeof(a))
using namespace std;
const int N = 1e3 + 10;
int n;
int dp[N][N];
int a[N];
int main()
{
while (~scanf("%d", &n) && n)
{
for (int i = 1; i <= n; i++)
{
scanf ("%d", &a[i]);
}
mst(dp, 0);
for (int i = 1; i <= n; i++)
{
dp[i][i] = 1;
}
for (int j = 1; j <= n; j++)
{
for (int i = 1; i + j <= n; i++)
{
dp[i][i + j] = max(dp[i + 1][i + j], dp[i][i + j - 1]);
if (a[i] == a[i + j])
{
dp[i][i + j] = max(dp[i][i + j], 2 + dp[i + 1][i + j - 1]);
}
}
}
int ans = 0;
for (int i = 1; i <= n; i++)
{
ans = max(ans, dp[1][i] + dp[i + 1][n]);
}
cout << ans << endl;
}
return 0;
}