您的位置:首页 > 其它

HDU 5693 D Game 区间dp

2016-05-23 15:05 375 查看

题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=5693

题解:

一种朴实的想法是枚举选择可以删除的两个或三个数(其他的大于三的数都能凑成2和3的和),删掉。然后一直递归下去。但删除子串的操作不容易,而且搜索复杂度有点大,记忆化判相同子序列也不容易。

可以看出,这些问题都是由于删除这个操作引起的。

因此为了保证dp的可操作性,我们没必要真的删除,另dp[l][r]表示区间[l,r]能删除的最大个数,如果dp[l][r]==r-l+1说明这一段是都可以删除的。这样子就可以用区间dp乱搞做出来了。

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;

const int maxn = 333;

int n, m;
int arr[maxn], mat[maxn][maxn],dp[maxn][maxn];

void init() {
memset(mat, 0, sizeof(mat));
memset(dp, 0, sizeof(dp));
}

void solve() {
//dp[l][r]==r-l+1说明l和r之间是可以全部删除掉的。
for (int len = 1; len <= n; len++) {
for (int l = 1; l <= n; l++) {
int r = l + len; if (r > n) break;
dp[l][r] = dp[l + 1][r - 1];
if (mat[l][r]&&dp[l + 1][r - 1] == r - l - 1)
dp[l][r] = max(dp[l][r], dp[l + 1][r - 1] + 2);

for (int i = l + 1; i < r; i++) {
if (mat[l][i] && dp[l + 1][i - 1] == i - l - 1)
dp[l][r] = max(dp[l][r], dp[l + 1][i - 1] + dp[i + 1][r] + 2);
if (mat[i][r] && dp[i + 1][r - 1] == r - i - 1)
dp[l][r] = max(dp[l][r], dp[l][i - 1] + dp[i + 1][r - 1] + 2);
if (mat[l][i] && mat[i][r] && arr[r] - arr[i] == arr[i] - arr[l] &&
dp[l + 1][i - 1] == i - l - 1 && dp[i + 1][r - 1] == r - i - 1) {
dp[l][r] = max(dp[l][r], r - l + 1);
}
}
//拆掉i,i+1的匹配。
for (int i = l; i <r; i++) {
dp[l][r] = max(dp[l][r], dp[l][i] + dp[i+1][r]);
}
}
}
}

int main() {
int tc;
scanf("%d", &tc);
while (tc--) {
scanf("%d%d", &n, &m); init();
for (int i = 1; i <= n; i++) scanf("%d", arr + i);
for (int i = 0; i < m; i++) {
int d; scanf("%d", &d);
for (int i = 1; i <= n; i++) {
for (int j = i + 1; j <= n; j++) {
if (arr[j] - arr[i] == d) mat[i][j] = 1;
}
}
}
solve();

printf("%d\n", dp[1]
);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: