• 读书笔记 ---- 0


    /**
    0-1 背包问题:经典动态规划入门题
    记忆化搜索方法:静态记录下递归过程中的状态值,避免重复计算
    
    在 n 个重量和价值分别是 wi 和 vi 的物品中挑选,使得物品重量总和
    不超过 W, 并且让其价值总和尽量大
    
    问题规模:
    1 <= n <= 100
    1 <= wi,vi <= 100
    1 <= W <= 10000
    状态转移方程:
    dp(i,S) = dp(i - 1, S - w[i]) + v[i]; // S - w[i] >= 0
    */
    
    #include <queue>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    typedef long long LL;
    const int MAXW = 10000 + 5;
    const int N = 100 + 5;
    int n,W;
    int w[N],v[N];
    int d[N][MAXW];
    
    int dp(int i, int S)
    {
        int &ans = d[i][S];
        if(ans != -1) return ans;
        ans = 0;
        if(i == 0)
            return ans;
        if(S - w[i] >= 0)
            ans =max(dp(i - 1, S), dp(i - 1, S - w[i]) + v[i]);
        else
            ans =dp(i-1, S);
        return ans;
    }
    void solve()
    {
        scanf("%d%d", &n, &W);
        for(int i = 1; i <= n ; i++)
            scanf("%d", w[i]);
        for(int i = 1; i <= n; i++)
            scanf("%d", v[i]);
        memset(d, -1, sizeof(d));
        dp(n, W);
    }
    int main()
    {
        solve();
        return 0;
    }
    /**
    0-1 背包问题:经典动态规划入门题
    
    在 n 个重量和价值分别是 wi 和 vi 的物品中挑选,使得物品重量总和
    不超过 W, 并且让其价值总和尽量大
    
    问题规模:
    1 <= n <= 100
    1 <= wi,vi <= 100
    1 <= W <= 10000
    状态转移方程:
    dp[i][j] = dp[i-1][j-w[i]] + v[i]; // j - w[i] >= 0
    */
    
    #include <queue>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    typedef long long LL;
    const int MAXW = 10000 + 5;
    const int N = 100 + 5;
    int n,W;
    int w[N],v[N];
    int dp[N][MAXW];
    
    void solve()
    {
        scanf("%d", &n, &W);
        for(int i = 1; i <= n ; i++)
            scanf("%d", w[i]);
        for(int i = 1; i <= n; i++)
            scanf("%d", v[i]);
        memset(d, 0, sizeof(d));
        for(int i = 1; i <= n; i++)
        {
            for(int j = 0; j <= W; j++)
            {
                if(j < w[i])
                    dp[i][j] = dp[i-1][j];
                else
                    dp[i][j] = max(dp[i-1][j], dp[i-1][j - w[i]] +v[i]);
            }
        }
        printf("%d
    ", dp[n][W]);
    }
    int main()
    {
        solve();
        return 0;
    }
    /**
    在 n 种重量和价值分别是 wi 和 vi 的物品中挑选,使得物品重量总和
    不超过 W, 并且让其价值总和尽量大
    
    问题规模:
    1 <= n <= 100
    1 <= wi,vi <= 100
    1 <= W <= 10000
    
    0-1背包:每种物品只有一个
    状态转移方程:dp[i][j] = max(dp[i-1][j] ,dp[i-1][j-w[i]]+v[i]);
    0-1背包的状态更新只跟上一层的考虑有关系
    
    完全背包:每种物品有无数个
    状态转移方程:dp[i][j] = max(dp[i-1][j],dp[i][j-w[i]]+v[i]);
    完全背包在本层中,需要考虑 对选择过本层物品后更新的状态 的使用,
    所以在实现上有所差别
    */
    
    #include <queue>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    typedef long long LL;
    const int MAXW = 10000 + 5;
    const int N = 100 + 5;
    int n,W;
    int w[N],v[N];
    int dp[MAXW];
    /**
    都使用一维数组来写
    */
    void solve_01()
    {
        scanf("%d", &n, &W);
        for(int i = 1; i <= n ; i++)
            scanf("%d", w[i]);
        for(int i = 1; i <= n; i++)
            scanf("%d", v[i]);
        memset(d, 0, sizeof(d));
        for(int i = 1; i <= n; i++)
        {
            for(int j = W; j >= 0; j--)
            {
                //这里使用的数据都是没有更新过的上层数据
                if(j >= w[i])
                    dp[j] = max(dp[j], dp[j - w[i]] +v[i]);
            }
        }
        printf("%d
    ", dp[n][W]);
    }
    
    void solve_entire()
    {
        scanf("%d", &n, &W);
        for(int i = 1; i <= n ; i++)
            scanf("%d", w[i]);
        for(int i = 1; i <= n; i++)
            scanf("%d", v[i]);
        memset(d, 0, sizeof(d));
        for(int i = 1; i <= n; i++)
        {
            for(int j = 0; j <= W; j++)
            {
                //这里使用的数据都是有更新过的上层数据
                if(j >= w[i])
                    dp[j] = max(dp[j], dp[j - w[i]] +v[i]);
            }
        }
        printf("%d
    ", dp[n][W]);
    }
    int main()
    {
        solve_01();
        return 0;
    }
    /**
    在 n 个重量和价值分别是 wi 和 vi 的物品中挑选,使得物品重量总和
    不超过 W, 并且让其价值总和尽量大
    
    问题规模:
    1 <= n <= 100
    1 <= vi <= 100
    1 <= wi <= 1e7
    1 <= W <= 1e9
    
    这题的重量的数量级比普通的背包扩大了10000倍,所以再使用之前的算法
    枚举重量状态O(n*W),次数量到达1e11,这将不是1s可以跑出来的方法。
    
    所以改变策略,状态描述为dp[i][j],考虑前i个物品价值总和为j的最小重量,
    状态转移方程:
    dp[i][j] = min(dp[i-1][j], dp[i-1][j-v[i]]+w[i]);
    然后从所有的价值状态中,找到重量合法的最大价值
    */
    
    #include <queue>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    typedef long long LL;
    const int MAXW = 1e9 + 5;
    const int MAXV = 1e5 + 5;
    const int N = 100 + 5;
    int n,W;
    int w[N],v[N];
    int dp[N][MAXV];
    
    void solve_entire()
    {
        int maxv = 0;
        scanf("%d", &n, &W);
        for(int i = 1; i <= n ; i++)
            scanf("%d", w[i]);
        for(int i = 1; i <= n; i++)
        {
            scanf("%d", v[i]);
            maxv += v[i];
        }
        memset(d, 0x3f, sizeof(d));
    
        for(int i = 1; i <= n; i++)
        {
            for(int j = 0; j <= maxv; j++)
            {
                if(j < v[i])
                    dp[i][j] = dp[i-1][j];
                else
                    dp[i][j] = min(dp[i-1][j], dp[i-1][j-v[i]]+w[i]);
            }
        }
        int ans = maxv;
        for(int i = maxv; i >= 0; i--)
        {
            if(dp[n][j] <= W)
            {
                ans = j;
                break;
            }
        }
        printf("%d
    ", ans);
    }
    int main()
    {
        solve();
        return 0;
    }



    如果有错误,请指出,谢谢
  • 相关阅读:
    P2486 [SDOI2011]染色 (树链剖分)
    机房测试:Dove打扑克(vector暴力)
    机房测试:sort(归并+概率期望dp)
    区间覆盖问题总结(贪心)
    机房测试:停不下来的团长奥加尔(dp)
    博客目录
    团队作业week16
    Beta阶段项目展示
    Beta阶段项目终审报告
    Beta阶段测试报告
  • 原文地址:https://www.cnblogs.com/Alruddy/p/7163197.html
Copyright © 2020-2023  润新知