zoukankan      html  css  js  c++  java
  • HDU 5693 D Game 区间dp

    题目链接:

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

    题解:

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

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

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

     1 #include<algorithm>
     2 #include<iostream>
     3 #include<cstring>
     4 #include<cstdio>
     5 using namespace std;
     6 
     7 const int maxn = 333;
     8 
     9 int n, m;
    10 int arr[maxn], mat[maxn][maxn],dp[maxn][maxn];
    11 
    12 void init() {
    13     memset(mat, 0, sizeof(mat));
    14     memset(dp, 0, sizeof(dp));
    15 }
    16 
    17 void solve() {
    18     //dp[l][r]==r-l+1说明l和r之间是可以全部删除掉的。
    19     for (int len = 1; len <= n; len++) {
    20         for (int l = 1; l <= n; l++) {
    21             int r = l + len; if (r > n) break;
    22             dp[l][r] = dp[l + 1][r - 1];
    23             if (mat[l][r]&&dp[l + 1][r - 1] == r - l - 1) 
    24                 dp[l][r] = max(dp[l][r], dp[l + 1][r - 1] + 2);
    25             
    26             for (int i = l + 1; i < r; i++) {
    27                 if (mat[l][i] && dp[l + 1][i - 1] == i - l - 1)
    28                     dp[l][r] = max(dp[l][r], dp[l + 1][i - 1] + dp[i + 1][r] + 2);
    29                 if (mat[i][r] && dp[i + 1][r - 1] == r - i - 1)
    30                     dp[l][r] = max(dp[l][r], dp[l][i - 1] + dp[i + 1][r - 1] + 2);
    31                 if (mat[l][i] && mat[i][r] && arr[r] - arr[i] == arr[i] - arr[l] &&
    32                     dp[l + 1][i - 1] == i - l - 1 && dp[i + 1][r - 1] == r - i - 1) {
    33                     dp[l][r] = max(dp[l][r], r - l + 1);
    34                 }
    35             }
    36             //拆掉i,i+1的匹配。
    37             for (int i = l; i <r; i++) {
    38                 dp[l][r] = max(dp[l][r], dp[l][i] + dp[i+1][r]);
    39             }
    40         }
    41     }
    42 }
    43 
    44 int main() {
    45     int tc;
    46     scanf("%d", &tc);
    47     while (tc--) {
    48         scanf("%d%d", &n, &m); init();
    49         for (int i = 1; i <= n; i++) scanf("%d", arr + i);
    50         for (int i = 0; i < m; i++) {
    51             int d; scanf("%d", &d);
    52             for (int i = 1; i <= n; i++) {
    53                 for (int j = i + 1; j <= n; j++) {
    54                     if (arr[j] - arr[i] == d) mat[i][j] = 1;
    55                 }
    56             }
    57         }
    58         solve();
    59 
    60         printf("%d
    ", dp[1][n]);
    61     }
    62     return 0;
    63 }
  • 相关阅读:
    e666. 创建缓冲图像
    e670. 缓冲图像转换为图像
    e680. 使三元色图像变明变暗
    e659. 缩放,剪取,移动,翻转图形
    e656. 创建基本图形
    e657. 用直线和曲线绘制图形
    e658. 组合图形
    e655. 混合风格的文本
    e654. 获得文本的缩略图
    e652. Getting the Font Faces for a Font Family
  • 原文地址:https://www.cnblogs.com/fenice/p/5520035.html
Copyright © 2011-2022 走看看