zoukankan      html  css  js  c++  java
  • 动态规划 —— 01背包问题

    01背包问题

    有n个重量和价值分别为wi,vi的物品。
    从这些物品中挑选出总重量不超过W的物品,
    求所有挑选方案中价值总和的最大值。

    针对每个物品是否放入背包进行搜索

    #include <iostream>
    
    #define MAX_N 100
    
    using namespace std;
    
    int n, W;
    int w[MAX_N], v[MAX_N];
    
    int rec(int i, int j) {      //从第i个物品开始挑选总重量小于j的部分
        int res;
    
        if (i == n) res = 0;    //已经没有剩余物品了
        else if (j < w[i]) res = rec(i + 1, j);     //无法挑选这个物品
        else res = max(rec(i + 1, j), rec(i + 1, j - w[i]) + v[i]);      //挑选和不挑选的两种情况都尝试一下
    
        return res;
    }
    
    int main() {
        cin >> n;
        for (int i = 0; i < n; i++)
            cin >> w[i] >> v[i];
        cin >> W;
        cout << rec(0, W) << endl;
        return 0;
    
    

    这种方法的搜索深度是n,而且每一层的搜索都需要两次分支,最坏就需要O(2n)的时间,当n比较大的时候就没办法解了。

    为了避免产生重复计算采用记忆化搜索

    #include <iostream>
    #include <cstring>
    
    #define MAX_N 100
    #define MAX_W 100
    
    using namespace std;
    
    int n, W;
    int w[MAX_N], v[MAX_N];
    int dp[MAX_N + 1][MAX_W + 1];
    
    int rec(int i, int j) {
        if (dp[i][j]) return dp[i][j];  //已经计算过的话直接使用之前的结果
    
        int res;
    
        if (i == n) res = 0;
        else if (j < w[i]) res = rec(i + 1, j);
        else res = max(rec(i + 1, j), rec(i + 1, j - w[i]) + v[i]);
    
        return dp[i][j] = res;
    }
    
    int main() {
        cin >> n;
        for (int i = 0; i < n; i++)
            cin >> w[i] >> v[i];
        cin >> W;
        memset(dp, 0, sizeof(dp));
        cout << rec(0, W);
        return 0;
    }
    

    对于同样的参数,只会在被调用到时执行递归部分,第二次之后都会直接返回。参数的组合不过nW种,而函数内只调用2次递归,所以只需要O(nW)的复杂度就能解决。

    DP数组

    记dp[i][j]根据rec的定义,从第i个物品开始挑选总重小于j时总价值的最大值。

    递推公式:
    dp[n][j]=0
    if(j<w[i]) dp[i][j]=dp[i+1][j]
    else dp[i][j]=max(rec(i+1,j),rec(i+1,j-w[i])+v[i])

    #include <iostream>
    
    #define MAX_N 100
    #define MAX_W 100
    
    using namespace std;
    
    int n, W;
    int w[MAX_N], v[MAX_N];
    int dp[MAX_N + 1][MAX_W + 1];
    
    int main() {
        cin >> n;
        for (int i = 0; i < n; i++)
            cin >> w[i] >> v[i];
        cin >> W;
        for (int i = n - 1; i > -1; i--) {
            for (int j = 0; j < W + 1; 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]);
            }
        }
        cout << dp[0][W];
        return 0;
    }
    
  • 相关阅读:
    PDF文件中的Form保存问题
    Understanding IP Fragmentation
    tcp ip guide IPsec IKE
    Windows安全事件日志中的事件编号与描述
    Cisco PIX fix up and Juniper firewall FTP ALG
    很好的IPSec介绍,详细解释了IKE协商的2个阶段的作用
    virtualbox 下运行Ubuntu 8.10的分辨率和guest additions的问题。
    Fixing the ‘Do you want to display nonsecure items’ message
    windows xp 开始菜单里面所有项目右键不起作用。
    HP backup and recovery manager
  • 原文地址:https://www.cnblogs.com/AlexKing007/p/12338304.html
Copyright © 2011-2022 走看看