zoukankan      html  css  js  c++  java
  • 0-1 背包

    今天就来说一下背包问题吧,就讨论最常说的 0-1 背包问题。描述:

    给你一个可装载重量为 W 的背包和 N 个物品,每个物品有重量和价值两个属性。其中第 i 个物品的重量为 wt[i],价值为 val[i],现在让你用这个背包装物品,最多能装的价值是多少?

     
     
     

    第一步要明确两点,「状态」和「选择」。

    先说状态,如何才能描述一个问题局面?只要给几个物品和一个背包的容量限制,就形成了一个背包问题呀。所以状态有两个,就是「背包的容量」和「可选择的物品」。

    再说选择,也很容易想到啊,对于每件物品,你能选择什么?选择就是「装进背包」或者「不装进背包」嘛。

    明白了状态和选择,动态规划问题基本上就解决了,只要往这个框架套就完事儿了:

    for 状态1 in 状态1的所有取值:
        for 状态2 in 状态2的所有取值:
            for ...
                dp[状态1][状态2][...] = 择优(选择1,选择2...)
    

     

    dp[i][w] 的定义如下:对于前 i 个物品,当前背包的容量为 w,这种情况下可以装的最大价值是 dp[i][w]

    比如说,如果 dp[3][5] = 6,其含义为:对于给定的一系列物品中,若只对前 3 个物品进行选择,当背包容量为 5 时,最多可以装下的价值为 6。

     

    int[][] dp[N+1][W+1]
    dp[0][..] = 0
    dp[..][0] = 0
    
    for i in [1..N]:
        for w in [1..W]:
            dp[i][w] = max(
                把物品 i 装进背包,
                不把物品 i 装进背包
            )
    return dp[N][W]

    二维 dp

    int main() {
        //可装载重量为 W 的背包和 N 个物品
        int N = 3, W = 4;
        std::vector<int> wt = {2, 1, 3};
        std::vector<int> val = {4, 2, 3};
        std::vector<std::vector<int>>dp(N+1,std::vector<int>(W+1,0));
        for(int n = 1;n <= N;++n) {
            for(int w = 1;w <= W;++w) {
                if(w-wt[n-1]< 0) {
                    dp[n][w] = dp[n-1][w];
                } else {
                    //由于i是从1开始的,所以 val 和 wt 的索引是 i-1 时表示第 i 个物品的价值和重量。
                    dp[n][w] = std::max(dp[n-1][w],val[n-1] + dp[n-1][w-wt[n-1]]); 
                }
            }
        }
        std::cout << dp[N][W] << std::endl;
        return 0;
    }

    二维 dp 投影到一维 dp

     一维dp

    注意一维 dp 遍历顺序。倒序防止覆盖

     1 #include<vector>
     2 #include<iostream>
     3 #include<string>
     4 int main() {
     5     //可装载重量为 W 的背包和 N 个物品
     6     int N = 3, W = 4;
     7     std::vector<int> wt = {2, 1, 3};
     8     std::vector<int> val = {4, 2, 3};
     9     std::vector<int>dp(W+1,0);
    10     for(int n = 1;n <= N;++n) {
    11         for(int w = W;w >=0;--w) {
    12             if(w-wt[n-1]< 0) {
    13                 dp[w] = dp[w];
    14             } else {
    15                 //由于i是从1开始的,所以 val 和 wt 的索引是 i-1 时表示第 i 个物品的价值和重量。
    16                 dp[w] = std::max(dp[w],val[n-1] + dp[w-wt[n-1]]); 
    17             }
    18         }
    19     }
    20     std::cout << dp[W] << std::endl;
    21     return 0;
    22 }

    https://mp.weixin.qq.com/s/xmgK7SrTnFIM3Owpk-emmg

  • 相关阅读:
    (Java实现) 洛谷 P1603 斯诺登的密码
    (Java实现) 洛谷 P1036 选数
    (Java实现) 洛谷 P1036 选数
    (Java实现) 洛谷 P1012 拼数
    (Java实现) 洛谷 P1012 拼数
    (Java实现) 洛谷 P1028 数的计算
    (Java实现) 洛谷 P1028 数的计算
    (Java实现) 洛谷 P1553 数字反转(升级版)
    8.4 确定两个日期之间的月份数或年数
    (Java实现) 洛谷 P1553 数字反转(升级版)
  • 原文地址:https://www.cnblogs.com/zle1992/p/15345811.html
Copyright © 2011-2022 走看看