• 动态规划(一)——0-1背包问题


    动态规划(1)——0-1背包问题

    1 题目描述

      对于一组不同重量、不可分割的物品,我们需要选择一些装入背包,在满足背包最大重量限制的前提下,背包中物品总重量的最大值是多少呢?

    2 输入

      第一行是物品的个数n(1≤n≤100000),背包容量w(1≤w≤1000000);
      第二行是n个物品的重量。

    3 输出

      输出最大值

    4 样例输入

    5 9
    2 2 4 6 3
    

    5 样例输出

    9
    

    6 求解思路

      把问题分解为多个阶段,每个阶段对应一个决策。我们记录每一个阶段可达的状态集合(去掉重复的),然后通过当前阶段的状态集合,来推导下一个阶段的状态集合,动态地往前推进。这也是动态规划这个名字的由来,你可以自己体会一下,是不是还挺形象的?

    7 C++版本代码如下

    #include <iostream>
    #include <math.h>
    #include <string.h>
    using namespace std;
    
    #define MAXNUM 100010
    
    int dpFirst(int weight[], int n, int weightLimit){
        bool states[n][weightLimit + 1];
        memset(states, false, sizeof(states));
        // 第一行单独处理
        states[0][0] = true;
        if(weight[0] <= weightLimit)
            states[0][weight[0]] = true;
    
        // 动态规划状态转移
        for(int i = 1; i < n; i++){
            for(int j = 0; j < weightLimit + 1; j++)
                if(states[i - 1][j]){
                    // 不装
                    states[i][j + 0] = true;
                    // 装
                    states[i][j + weight[i]] = true;
                }
        }
        // 找出最后一个状态下的背包值
        int maxPower = 0;
        for(int i = 0; i <= weightLimit; i++)
            if(states[n - 1][i])
                maxPower = i;
        return maxPower;
    }
    
    int main()
    {
        int weight[5] = {2,2,4,6,3};
        cout<<dpFirst(weight, 5, 9)<<endl;;
        return 0;
    }
    

      因为只需要判断最后一个状态下的背包容量,所以可以使用一个数组states[weightLimit]即可解决问题,代码可优化空间复杂度如下:
      其中注意上一个二维数组的方法中数组weight的访问可能越界,所以修改为j <= weightLimit - weight[i + 1]保证了数组weight不会越界,表示“当前状态”能装下的。

    int dpFirst(int weight[], int n, int weightLimit){
        bool states[weightLimit + 1];
        memset(states, false, sizeof(states));
        // 单独处理第一个状态
        states[0] = true;
        if(weight[0] <= weightLimit)
            states[weight[0]] = true;
    
        // 动态规划状态转移用一个数组解决
        for(int i = 1; i < n; i++){
            // 可以直接写成weightLimit - weight[i],而不是weightLimit
            // 这样可以少几个判断,并且保证了数组weight不会越界
            for(int j = 0; j <= weightLimit - weight[i]; j++){
                if(states[j])
                    // 装
                    states[j+ weight[i]] = true;
            }
        }
    
        // 找出最后一个状态下的背包值
        for(int i = weightLimit; i >= 0; i--)
            if(states[i])
                return i;
    }
    
  • 相关阅读:
    easyui 如何引入
    图片切换展示效果
    渐变弹出层
    C# GEP基因化编程
    C#操作内存
    移动的彩虹
    收缩和展开效果
    用SQL语句,删除掉重复项只保留一条
    图片切换,带标题文字
    Sql Server快速建表
  • 原文地址:https://www.cnblogs.com/flyingrun/p/13495653.html
Copyright © 2020-2023  润新知