C. Arcade dp二维费用背包 + 滚动数组 玄学

http://codeforces.com/gym/101257/problem/C

询问从左上角走到右下角,每次只能向右或者向左,捡起三种物品算作一个logo,求最多能得到多少个logo。

设dp[i][j][k][h]表示走到(i, j)这个格子,然后得到的第一种物品是k,第二种物品是h的时候,能得到的第三个物品的最大值是多少。

-inf表示不存在这个状态,其实第三种物品可以算出来,因为一共的步数就是i + j - 1,所以捡起的物品数量是固定的。

所以直接这样dp下去即可,是一个背包问题。

然后会MLE,所以我把第一维滚动了。(不会把第二维也滚动,一直出不了样例)

有一个小bug就是,每种物品最多都是可以捡200个,n + m - 1个,一定要都枚举是否成立。

一开始我只枚举到67个,因为67 * 3 = 201,logo数目其实最多就是66

但是会wa。还想不到数据

可能dp应该是要遍历所有可能的结果,只不过是选最优,有一些部分被抛弃了而已。

所以枚举到200吧,毕竟它最多能捡起200个。

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <assert.h>
#define IOS ios::sync_with_stdio(false)
using namespace std;
#define inf (0x3f3f3f3f)
typedef long long int LL;


#include <iostream>
#include <sstream>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <string>
#include <bitset>
const int maxn = 1e2 + 2;
char str[maxn][maxn];
int n, m;
int dp[4][maxn][200 + 2][200 + 2];
int pre(int id) {
    if (id == 0) return 2;
    else return id - 1;
}
void work() {
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; ++i) {
        scanf("%s", str[i] + 1);
    }
    memset(dp, -0x3f, sizeof dp);
    dp[0][1][0][0] = 0;
    dp[1][0][0][0] = 0;
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= m; ++j) {
            int en = i + j - 1;
            for (int k = en; k >= 0; --k) {
                for (int h = en; h >= 0; --h) {
                    dp[i % 3][j][k][h] = -inf;
                    if (str[i][j] == '>') {
                        if (k < 1) {
                            dp[i % 3][j][k][h] = -inf;
                            continue;
                        }
                        dp[i % 3][j][k][h] = dp[pre(i % 3)][j][k - 1][h];
                        dp[i % 3][j][k][h] = max(dp[i % 3][j][k][h], dp[i % 3][j - 1][k - 1][h]);
                    } else if (str[i][j] == '|') {
                        if (h < 1) {
                            dp[i % 3][j][k][h] = -inf;
                            continue;
                        }
                        dp[i % 3][j][k][h] = dp[pre(i % 3)][j][k][h - 1];
                        dp[i % 3][j][k][h] = max(dp[i % 3][j][k][h], dp[i % 3][j - 1][k][h - 1]);
                    } else {
                        dp[i % 3][j][k][h] = dp[pre(i % 3)][j][k][h] + 1;
                        dp[i % 3][j][k][h] = max(dp[i % 3][j][k][h], dp[i % 3][j - 1][k][h] + 1);
                    }
                }
            }
        }
    }
    int ans = 0;
    for (int i = 0; i <= 200; ++i) {
        for (int j = 0; j <= 200; ++j) {
            ans = max(ans, min(i, min(j, dp[n % 3][m][i][j])));
//            if (dp[n % 3][m][i][j] >= 0) {
//                cout << i << " " << j << " " << dp[n % 3][m][i][j] << endl;
//            }
        }
    }
    cout << ans << endl;

}

int main() {
#ifdef local
    freopen("data.txt", "r", stdin);
//    freopen("data.txt", "w", stdout);
#endif
    work();
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/liuweimingcprogram/p/6417357.html