IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 01背包问题 -> 正文阅读

[数据结构与算法]01背包问题

一、0-1背包问题的状态转移方程

设F(n, C)考虑将n个物品放进容量为C的背包中,使得价值最大。
对于F(i, c)有两种选择:
(1)对于第i个物品不需要放入背包中,则该问题就变成F(i - 1, c)
(2)对于第i个物品需要放入背包中,则该问题就变成F(i - 1, c - w(i)) + v(i)
在二种选择选择最大值就为01背包的解,为:

F(i, c) = max(F(i - 1, c), F(i - 1, c - w(i)) + v(i))

时间复杂度:O(n * c);空间复杂度:O(n * c)
代码如下

private static int bestValueDynamic(int[] w, int[] v) {
    int[][] res = new int[n][c + 1];

    for (int i = 0; i <= c; i ++) {
        res[0][i] = i >= w[0] ? v[0] : 0;
    }

    for (int i = 1; i < n; i ++) {
        for (int j = 0; j <= c; j ++) {
            res[i][j] = res[i - 1][j];
            if (j >= w[i]) {
                res[i][j] = Math.max(res[i][j], v[i] + res[i - 1][j - w[i]]);
            }
        }
    }
    return res[n - 1][c];
}

二、算法的优化

根据状态转移方程,第i行元素只依赖于第i-1行元素,因此理论上只需要保持两行矩阵即可。则空间复杂度就为O(n)。

同时由于一个元素只依赖自己左边的元素,因此就需要一维数组即可,但是需要逆序遍历。
代码实现:

// 动态规划的优化,只使用一维数组,只参考上边和左边的内容,可以只用一个一维数组,需要逆序遍历
// 时间复杂度:O(n * c);空间复杂度:O(n)
private static int bestValueDynamic(int[] w, int[] v) {
    int[] res = new int[c + 1];

    for (int i = 0; i <= c; i ++) {
        res[i] = i >= w[0] ? v[0] : 0;
    }

    for (int i = 1; i < n; i ++) {
        for (int j = c; j >= w[i]; j --) {
            res[j] = Math.max(res[j], v[i] + res[j - w[i]]);
        }
    }
    return res[c];
}

三、0-1背包的变种

完全背包的问题:每个物品可以无限使用

多重背包问题:每个物品不止一个,有nums[i]个

多维费用背包问题:要考虑物品的体积和重量两个维度

四、leetcode相关题目

416、474、377、139、494

五、关于0-1背包地思考

在leetcode很多题目本质上就是0-1背包问题,例如一类问题就是从一个数组中选出数的和为一个给定值,这就是一个0-1背包问题。此外0-1背包分为以下几种:
1、只在乎最大价值,这类问题就是以上讨论的;
2、保证容量被装满,这类问题就是组合和问题,在这类问题中,也需要区分顺序问题和重复问题。
(1)如果不考虑顺序和重复,就是排列和问题,例如leetcode 377。
状态方程为:

F(s) = sum(F(s - num[i]))

代码为:

// target就是背包容量
int[] res = new int[c + 1];
res[0] = 1;
for (int j = 1; j <= c; j ++) {
    for (int i = 0; i < nums.length; i ++) {
        if (j >= nums[i]) {
            res[j] += res[j - nums[i]];
        }
    }
}

(2)考虑顺序,元素可以无限使用,就是完全背包问题,例如leetcode 518
状态方程为:F(k,i) = F(k-1, i) + F(k - 1, i-nums[k])
F(k,i)表示k个数可以凑成i的方法数,分为两种情况
代码为:

int[] res = new int[c + 1];
res[0] = 1;
for (int num : nums) {
    for (int i = num; i <= c; i ++) {
        res[i] += res[i - num];
    }
}

(3)元素只能使用一次,就是01背包问题,例如leetcode494
代码为:

int[] res = new int[c + 1];
res[0] = 1;
for (int i = 0; i < nums.length; i ++) {
    for (int j = c; j >= nums[i]; j --) {
        res[j] += res[j - nums[i]];
    }
}

我们可以看出以上的状态方程是一致的,只要是代码循环方式不一致。

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-01-12 00:15:37  更:2022-01-12 00:19:25 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 18:31:23-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码