墨风如雪博客

  • 源码小店
  • 传家宝VPS
让AI使用变得如此简单
  1. 首页
  2. 算法
  3. 正文

每日一道算法题:背包问题

2023年 6月 6日 190点热度 0人点赞 0条评论

背包问题详解

一、背包问题介绍

A. 定义

背包问题是一个经典的组合优化问题,指在给定容量和一组物品的情况下,需要选择一些物品放入容器中,使得总体价值最大化,同时不超过容器的容量限制。

B. 实际应用场景

背包问题在实际生活中具有广泛的应用,如货车或背包装载物品数量和重量的决策、投资组合、硬件资源分配等。

C. 算法求解方式

背包问题可以通过多种算法求解,其中动态规划和贪心算法是解决背包问题的主要方法。在不同场景下可能需要用到不同的算法。

二、01背包问题

A. 问题描述

在一组物品中,每个物品仅有一件,容量和价值是已知的,需要从中选择若干件物品放入背包中,使得背包的容量不超过限制,且所选物品的总价值最大。

B. 解决方案

1. 动态规划算法

使用动态规划算法先求出每个不同容量下的最大价值,再逐步向上推得到全局最优解。时间复杂度为 O(nW),n表示物品数量,W表示背包容量。

public static int knapsack01DP(int[] volumes, int[] values, int maxVolume) {
    int[][] dp = new int[volumes.length + 1][maxVolume + 1];
    for (int i = 1; i <= volumes.length; i++) {
        for (int j = 1; j <= maxVolume; j++) {
            if (j - volumes[i - 1] >= 0) {
                dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - volumes[i - 1]] + values[i - 1]);
            } else {
                dp[i][j] = dp[i - 1][j];
            }
        }
    }
    return dp[volumes.length][maxVolume];
}

2. 贪心算法

使用贪心算法从大到小排序物品,每次选择能放入背包且价值最大的物品放入背包。时间复杂度为 O(nlogn),其中n表示物品数量。

public static int knapsack01Greedy(int[] volumes, int[] values, int maxVolume) {
    int[] valueDensity = new int[volumes.length];
    for (int i = 0; i < volumes.length; i++) {
        valueDensity[i] = values[i] / volumes[i];
    }
    int maxValue = 0;
    for (int i = 0; i < volumes.length; i++) {
        int maxIndex = getMaxIndex(valueDensity);
        if (maxIndex != -1) {
            if (maxVolume >= volumes[maxIndex]) {
                maxVolume -= volumes[maxIndex];
                maxValue += values[maxIndex];
                valueDensity[maxIndex] = -1;
            } else {
                maxValue += valueDensity[maxIndex] * maxVolume;
                maxVolume = 0;
                break;
            }
        } else {
            break;
        }
    }
    return maxValue;
}

C. 算法复杂度分析

动态规划算法和贪心算法的时间复杂度相比,贪心算法更快,但不能保证得到全局最优解。在某些情况下,贪心算法得到的解可能并不是最优解。

三、完全背包问题

A. 问题描述

在一组物品中,每个物品有无穷个,容量和价值是已知的,需要从中选择若干个物品放入背包中,使得背包的容量不超过限制,且所选物品的总价值最大。

B. 解决方案

1. 动态规划算法

完全背包问题可以看作是01背包问题的扩展,因此可以使用类似的动态规划算法,在算法的内层循环时,将取之前看成不同的状态下取,即可求得最大价值。时间复杂度为 O(nW)。

public static int knapsackFullDP(int[] volumes, int[] values, int maxVolume) {
    int[][] dp = new int[volumes.length + 1][maxVolume + 1];
    for (int i = 1; i <= volumes.length; i++) {
        for (int j = 1; j <= maxVolume; j++) {
            if (j - volumes[i - 1] >= 0) {
                int maxItemCount = j / volumes[i - 1];
                int maxValue = 0;
                for (int k = 0; k <= maxItemCount; k++) {
                    maxValue = Math.max(maxValue, dp[i - 1][j - k * volumes[i - 1]] + k * values[i - 1]);
                }
                dp[i][j] = maxValue;
            } else {
                dp[i][j] = dp[i - 1][j];
            }
        }
    }
    return dp[volumes.length][maxVolume];
}

2. 贪心算法

完全背包问题可以将贪心算法变为一种动态策略算法,选择每一件物品时都基于上一步所花费的容量和本次所花费的容量进行相互参考,选择能放入背包且价值较高的物品进行放置。时间复杂度为O(nlogn),其中n表示物品数量。

public static int knapsackFullGreedy(int[] volumes, int[] values, int maxVolume) {
    int[] valueDensity = new int[volumes.length];
    for (int i = 0; i < volumes.length; i++) {
        valueDensity[i] = values[i] / volumes[i];
    }
    int maxValue = 0;
    for (int i = 0; i < maxVolume; i++) {
        int maxIndex = getMaxIndex(valueDensity);
        if (maxIndex != -1) {
            if (maxVolume >= volumes[maxIndex]) {
                maxVolume -= volumes[maxIndex];
                maxValue += values[maxIndex];
            } else {
                maxValue += valueDensity[maxIndex] * maxVolume;
                maxVolume = 0;
                break;
            }
        } else {
            break;
        }
    }
    return maxValue;
}

C. 算法复杂度分析

完全背包问题的动态规划算法和01背包问题的动态规划算法非常类似,因此时间复杂度也一样,为 O(nW)。贪心算法的时间复杂度为O(nlogn)。

本作品采用 知识共享署名 4.0 国际许可协议 进行许可
标签: java 动态规划 完全背包问题 算法 背包问题 解析
最后更新:2023年 5月 27日

墨风如雪

一个热爱生活,热爱分享的程序员

打赏 点赞
< 上一篇
下一篇 >

文章评论

您需要 登录 之后才可以评论

墨风如雪

一个热爱生活,热爱分享的程序员

最新 热点 随机
最新 热点 随机
腾讯混元MT-7B:打破参数迷思,重塑机器翻译版图 瑞士AI宣言:Apertus如何定义开放大模型 月之暗面Kimi K2-0905:代码与创意的新篇章? 谷歌“蕉”傲登场!AI生图告别“走钟”时代 2025,AI世界模型新篇章:腾讯混元Voyager展望 单GPU秒产一分钟!MAI-Voice-1,微软语音AI的“核爆”时刻?
别再卷万亿参数了,这个4B模型正把AI工作站塞进你的手机全球最佳开放模型!OpenAI开源GPT-OSS,AI界迎来巨变!声音即影像:昆仑万维SkyReels-A3如何叩响内容创作的革命前夜9B参数硬撼72B,GLM-4.1V凭什么搅动AI江湖?2B参数掀翻巨头牌桌:昆仑万维UniPic 2.0的“四两拨千斤”天工V2发布:AI终于撕掉了“纯文本”的标签
美团炸场AI圈:点外卖点出个软件?用「对话式编程」重塑生产力! 小红书AI新里程碑:dots.llm1,中文MoE的“人文”突破! 告别AI视频“幻觉”:群核SpatialGen,3D生成驶入“真空间”时代! AI理财新秀Kuvera-8B:同理心与钱袋子的秘密 Java 当中的只要组成部分 JVM 火速围观!Trae IDE 迎来两大明星模型,Kimi K2 硬核登场,Grok-4 (Beta) 闪耀国际!
标签聚合
设计模式 大模型 算法 java spring deepseek AI 教程

COPYRIGHT © 2023 墨风如雪博客. ALL RIGHTS RESERVED.

Theme Kratos Made By Seaton Jiang