牛客-装货物

题目传送门

sol:题目的数据范围就是对解决方案的一种提示,原先以为当数据范围只有$20$的时候都是dfs或者二进制枚举这种,从这题了解到还有状压dp。不解释了,反正就是状压dp,做的不多,记录一下。

  • 状压dp
    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef pair<int, int> PII;
    const int INF = 0x3f3f3f3f;
    const int MAXN = 22;
    int a[MAXN];
    // dp1最小箱子消耗,dp2在最小箱子消耗的前提下最后一个箱子的最大剩余
    int dp1[1 << MAXN | 10], dp2[1 << MAXN | 10];
    int main() {
        int t; scanf("%d", &t);
        while (t--) {
            int n, m, w, _max = 0;
            scanf("%d%d%d", &n, &m, &w);
            for (int i = 0; i < n; i++) { //状压dp下标还是从0开始好了,从1开始写了几次都wa
                scanf("%d", &a[i]);
                _max = max(_max, a[i]);
            }
            if (_max > w) {
                puts("No");
                continue;
            }
            memset(dp1, INF, sizeof(int) * (1 << n));
            memset(dp2, 0, sizeof(int) * (1 << n));
            dp1[0] = 0;
            for (int i = 0; i < (1 << n); i++) {
                for (int j = 0; j < n; j++) {
                    int k = 1 << j;
                    if (i & k) continue;
                    if (dp2[i] >= a[j] && (dp1[i] < dp1[i | k] || dp1[i] == dp1[i | k] && dp2[i | k] < dp2[i] - a[j])) {
                        dp1[i | k] = dp1[i];
                        dp2[i | k] = dp2[i] - a[j];
                    } else if (dp1[i] + 1 <= dp1[i | k]) {
                        dp1[i | k] = dp1[i] + 1;
                        dp2[i | k] = w - a[j];
                    }
                }
            }
    //        printf("%d
    ", dp1[(1 << n) - 1]);
            puts(dp1[(1 << n) - 1] <= m ? "Yes" : "No");
        }
        return 0;
    }
  • 爆搜
    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef pair<int, int> PII;
    int a[30], c[30];
    int n, m, w;
    bool dfs(int i) {
        if (i > n) return true;
        int k = min(i + 1, m); // 这个优化很关键
        for (int j = 1; j <= k; j++) {
            if (c[j] + a[i] <= w) {
                c[j] += a[i];
                if (dfs(i + 1)) return true;
                c[j] -= a[i];
            }
        }
        return false;
    }
    int main() {
        int t; scanf("%d", &t);
        while (t--) {
            scanf("%d%d%d", &n, &m, &w);
            for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
            sort(a + 1, a + 1 + n, greater<int>());
            if (a[1] > w) {
                puts("No");
                continue;
            }
            if (m >= n) {
                puts("Yes");
                continue;
            }
            memset(c, 0, sizeof(c));
            puts(dfs(1) ? "Yes" : "No");
        }
        return 0;
    }

    数据比较水,在爆搜优化到极致的情况下能AC,自己写的时候没有那个关键的优化总是超时,还是挺妙的。

原文地址:https://www.cnblogs.com/Angel-Demon/p/12188015.html