• 洛谷P4141 消失之物 题解 背包问题扩展


    题目链接:https://www.luogu.com.cn/problem/P4141

    题目大意:
    (n) 件物品,求第 (i) 件物品不能选的时候((i)(1)(n))0-1背包方案数。

    解题思路:

    传统方法

    遍历每一遍不选的物品,然后对剩余的物品求01背包方案数。
    时间复杂度为 (O(n^2m))

    由于这里每一件物品的价值和时间相同,
    所以可以定义状态 (f[i]) 表示填满体积 (i) 的方案数。

    则有状态转移方程:
    (f[0] = 1)
    (f[i] = sum f[i-c]) (其中 (c) 对应每一件物品的体积)

    实现代码如下:

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 2020;
    int n, V, w[maxn], f[maxn];
    void pack(int c) {
        for (int i = V; i >= c; i --)
            f[i] = (f[i] + f[i-c]) % 10;
    }
    void solve(int id) {
        memset(f, 0, sizeof(f));
        f[0] = 1;
        for (int i = 0; i < n; i ++) {
            if (i == id) continue;
            pack(w[i]);
        }
        for (int i = 1; i <= V; i ++) cout << f[i];
        cout << endl;
    }
    int main() {
        cin >> n >> V;
        for (int i = 0; i < n; i ++) cin >> w[i];
        for (int i = 0; i < n; i ++) solve(i);
        return 0;
    }
    

    优化

    转载自 Kelin大神的博客

    其实只要跑一次背包(全部物品都在)
    然后我们考虑少了某个物品怎么办?
    我们在01背包DP时会用到这个转移

    for(int j=m;j>=w[i];--j)
        f[j]+=f[j-w[i]];
    

    我们少了i物品就是在原来的基础上少了一次这样的转移
    所以我们在原来的基础上顺推减去这样的一次转移就ok了

    memcpy(g,f,sizeof f);
    for(int j=w[i];j<=m;++j)
        g[j]-=g[j-w[i]];
    

    实现代码如下:

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 2020;
    int n, V, w[maxn], f[maxn], g[maxn];
    void pack(int c) {
        for (int i = V; i >= c; i --)
            f[i] = (f[i] + f[i-c]) % 10;
    }
    void unpack(int c) {
        memcpy(g, f, sizeof(f));
        for (int i = c; i <= V; i ++)
            g[i] = (g[i] - g[i-c] + 10) % 10;
    }
    void init() {
        memset(f, 0, sizeof(f));
        f[0] = 1;
        for (int i = 0; i < n; i ++) {
            pack(w[i]);
        }
    }
    void solve(int id) {
        unpack(w[id]);
        for (int i = 1; i <= V; i ++) cout << g[i];
        cout << endl;
    }
    int main() {
        cin >> n >> V;
        for (int i = 0; i < n; i ++) cin >> w[i];
        init();
        for (int i = 0; i < n; i ++) solve(i);
        return 0;
    }
    
  • 相关阅读:
    python 的class和def 定义执行语句相关
    python _和__ 下划线命名规则
    python2和python3编码问题【encode和decode】
    cpython源码阅读
    eCPRI
    python内存管理/垃圾回收
    Class() vs self.__class__()
    JAVA学习日报 11/24
    JAVA学习日报 11/23
    JAVA学习日报 11/22
  • 原文地址:https://www.cnblogs.com/quanjun/p/12024862.html
Copyright © 2020-2023  润新知