- 算法设计与分析
- 家
- 算法基础知识
- DAA - 简介
- DAA - 算法分析
- DAA-分析方法
- 渐近符号和先验分析
- 时间复杂度
- 马斯特定理
- DAA - 空间复杂性
- 分而治之
- DAA-分而治之
- DAA - 最大最小问题
- DAA-归并排序
- DAA-二分查找
- 施特拉森矩阵乘法
- 唐叶算法
- 河内塔
- 贪心算法
- DAA-贪婪法
- 旅行商问题
- Prim 的最小生成树
- 克鲁斯卡尔的最小生成树
- Dijkstra 的最短路径算法
- 地图着色算法
- DAA-分数背包
- DAA - 带截止日期的作业排序
- DAA - 最佳合并模式
- 动态规划
- DAA-动态规划
- 矩阵链乘法
- 弗洛伊德·沃歇尔算法
- DAA - 0-1 背包
- 最长公共子序列
- 旅行商问题| 动态规划
- 随机算法
- 随机算法
- 随机快速排序
- 卡格的最低削减
- 费舍尔-耶茨洗牌
- 近似算法
- 近似算法
- 顶点覆盖问题
- 设置封面问题
- 旅行推销员近似算法
- 排序技巧
- DAA-快速排序
- DAA-冒泡排序
- DAA——插入排序
- DAA-选择排序
- DAA——希尔排序
- DAA-堆排序
- DAA——桶排序
- DAA——计数排序
- DAA - 基数排序
- 搜索技巧
- 搜索技术介绍
- DAA - 线性搜索
- DAA-二分查找
- DAA - 插值搜索
- DAA - 跳转搜索
- DAA - 指数搜索
- DAA - 斐波那契搜索
- DAA - 子列表搜索
- DAA-哈希表
- 图论
- DAA-最短路径
- DAA - 多级图
- 最优成本二叉搜索树
- 堆算法
- DAA-二叉堆
- DAA-插入法
- DAA-Heapify 方法
- DAA-提取方法
- 复杂性理论
- 确定性计算与非确定性计算
- DAA-最大派系
- DAA - 顶点覆盖
- DAA - P 级和 NP 级
- DAA-库克定理
- NP 硬课程和 NP 完全课程
- DAA - 爬山算法
- DAA 有用资源
- DAA - 快速指南
- DAA - 有用的资源
- DAA - 讨论
设计与分析 - 分数背包
背包问题指出 - 给定一组物品、持有重量和利润值,必须确定要添加到背包中的物品的子集,使得物品的总重量不得超过背包的限制,并且其总利润值最大。
这是采用贪心方法解决的最流行的问题之一。它被称为分数背包问题。
为了更容易地解释这个问题,考虑一个有 12 个问题的测试,每个问题 10 分,其中只有 10 个问题应该尝试以获得最高分 100 分。现在,考生必须计算出利润最高的问题 - 他认为是最有利的问题。有信心——取得最高分。然而,他无法尝试全部 12 个问题,因为这些尝试的答案不会获得任何额外分数。这是背包问题最基本的现实应用。
背包算法
将要添加到背包中的物品的重量(Wi)和利润值(Pi)作为分数背包算法的输入,并获得添加到背包中的物品的子集而不超过限制且利润最大作为输出。
算法
考虑所有物品及其分别提到的重量和利润。
计算所有项目的 P i /W i并根据其 P i /W i值按降序对项目进行排序。
在不超过限制的情况下,将物品添加到背包中。
如果背包还能储存一些重量,但其他物品的重量超过限制,则可以添加下次的小数部分。
因此,将其命名为分数背包问题。
例子
对于给定的一组物品和 10 公斤的背包容量,找到要添加到背包中的物品的子集,使得利润最大。
项目 | 1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|---|
重量(公斤) | 3 | 3 | 2 | 5 | 1 |
利润 | 10 | 15 | 10 | 12 | 8 |
解决方案
步骤1
给定,n = 5
Wi = {3, 3, 2, 5, 1} Pi = {10, 15, 10, 12, 8}
计算所有项目的P i /W i
项目 | 1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|---|
重量(公斤) | 3 | 3 | 2 | 5 | 1 |
利润 | 10 | 15 | 10 | 20 | 8 |
皮/维_ | 3.3 | 5 | 5 | 4 | 8 |
第2步
根据 P i /W i将所有项目按降序排列
项目 | 5 | 2 | 3 | 4 | 1 |
---|---|---|---|---|---|
重量(公斤) | 1 | 3 | 2 | 5 | 3 |
利润 | 8 | 15 | 10 | 20 | 10 |
皮/维_ | 8 | 5 | 5 | 4 | 3.3 |
步骤3
在不超过背包容量的情况下,以最大利润将物品放入背包中。
Knapsack = {5, 2, 3}
然而,背包仍然可以容纳 4 公斤的重量,但下一个重量为 5 公斤的物品将超出容量。因此,背包中只会添加5公斤中的4公斤重量。
项目 | 5 | 2 | 3 | 4 | 1 |
---|---|---|---|---|---|
重量(公斤) | 1 | 3 | 2 | 5 | 3 |
利润 | 8 | 15 | 10 | 20 | 10 |
背包 | 1 | 1 | 1 | 4/5 | 0 |
因此,背包里的重量 = [(1 * 1) + (1 * 3) + (1 * 2) + (4/5 * 5)] = 10,最大利润为 [(1 * 8) + ( 1 * 15) + (1 * 10) + (4/5 * 20)] = 37。
例子
以下是使用贪心法的分数背包算法的最终实现 -
#include <stdio.h> int n = 5; int p[10] = {3, 3, 2, 5, 1}; int w[10] = {10, 15, 10, 12, 8}; int W = 10; int main(){ int cur_w; float tot_v; int i, maxi; int used[10]; for (i = 0; i < n; ++i) used[i] = 0; cur_w = W; while (cur_w > 0) { maxi = -1; for (i = 0; i < n; ++i) if ((used[i] == 0) && ((maxi == -1) || ((float)w[i]/p[i] > (float)w[maxi]/p[maxi]))) maxi = i; used[maxi] = 1; cur_w -= p[maxi]; tot_v += w[maxi]; if (cur_w >= 0) printf("Added object %d (%d, %d) completely in the bag. Space left: %d.\n", maxi + 1, w[maxi], p[maxi], cur_w); else { printf("Added %d%% (%d, %d) of object %d in the bag.\n", (int)((1 + (float)cur_w/p[maxi]) * 100), w[maxi], p[maxi], maxi + 1); tot_v -= w[maxi]; tot_v += (1 + (float)cur_w/p[maxi]) * w[maxi]; } } printf("Filled the bag with objects worth %.2f.\n", tot_v); return 0; }
输出
Added object 5 (8, 1) completely in the bag. Space left: 9. Added object 2 (15, 3) completely in the bag. Space left: 6. Added object 3 (10, 2) completely in the bag. Space left: 4. Added object 1 (10, 3) completely in the bag. Space left: 1. Added 19% (12, 5) of object 4 in the bag. Filled the bag with objects worth 45.40.
#include <iostream> int n = 5; int p[10] = {3, 3, 2, 5, 1}; int w[10] = {10, 15, 10, 12, 8}; int W = 10; int main(){ int cur_w; float tot_v; int i, maxi; int used[10]; for (i = 0; i < n; ++i) used[i] = 0; cur_w = W; while (cur_w > 0) { maxi = -1; for (i = 0; i < n; ++i) if ((used[i] == 0) && ((maxi == -1) || ((float)w[i]/p[i] > (float)w[maxi]/p[maxi]))) maxi = i; used[maxi] = 1; cur_w -= p[maxi]; tot_v += w[maxi]; if (cur_w >= 0) printf("Added object %d (%d, %d) completely in the bag. Space left: %d.\n", maxi + 1, w[maxi], p[maxi], cur_w); else { printf("Added %d%% (%d, %d) of object %d in the bag.\n", (int)((1 + (float)cur_w/p[maxi]) * 100), w[maxi], p[maxi], maxi + 1); tot_v -= w[maxi]; tot_v += (1 + (float)cur_w/p[maxi]) * w[maxi]; } } printf("Filled the bag with objects worth %.2f.\n", tot_v); return 0; }
输出
Added object 5 (8, 1) completely in the bag. Space left: 9. Added object 2 (15, 3) completely in the bag. Space left: 6. Added object 3 (10, 2) completely in the bag. Space left: 4. Added object 1 (10, 3) completely in the bag. Space left: 1. Added 19% (12, 5) of object 4 in the bag. Filled the bag with objects worth 45.40.
public class Main { static int n = 5; static int p[] = {3, 3, 2, 5, 1}; static int w[] = {10, 15, 10, 12, 8}; static int W = 10; public static void main(String args[]) { int cur_w; float tot_v = 0; int i, maxi; int used[] = new int[10]; for (i = 0; i < n; ++i) used[i] = 0; cur_w = W; while (cur_w > 0) { maxi = -1; for (i = 0; i < n; ++i) if ((used[i] == 0) && ((maxi == -1) || ((float)w[i]/p[i] > (float)w[maxi]/p[maxi]))) maxi = i; used[maxi] = 1; cur_w -= p[maxi]; tot_v += w[maxi]; if (cur_w >= 0) System.out.println("Added object " + maxi + 1 + " (" + w[maxi] + "," + p[maxi] + ") completely in the bag. Space left: " + cur_w); else { System.out.println("Added " + ((int)((1 + (float)cur_w/p[maxi]) * 100)) + "% (" + w[maxi] + "," + p[maxi] + ") of object " + (maxi + 1) + " in the bag."); tot_v -= w[maxi]; tot_v += (1 + (float)cur_w/p[maxi]) * w[maxi]; } } System.out.println("Filled the bag with objects worth " + tot_v); } }
输出
Added object 41 (8,1) completely in the bag. Space left: 9 Added object 11 (15,3) completely in the bag. Space left: 6 Added object 21 (10,2) completely in the bag. Space left: 4 Added object 01 (10,3) completely in the bag. Space left: 1 Added 19% (12,5) of object 4 in the bag. Filled the bag with objects worth 45.4
n = 5 p = [3, 3, 2, 5, 1] w = [10, 15, 10, 12, 8] W = 10 cur_w = W tot_v = 0 used = [0] * 10 for i in range(n): used[i] = 0 while cur_w > 0: maxi = -1 for i in range(n): if (used[i] == 0) and ((maxi == -1) or ((w[i] / p[i]) > (w[maxi] / p[maxi]))): maxi = i used[maxi] = 1 cur_w -= p[maxi] tot_v += w[maxi] if cur_w >= 0: print(f"Added object {maxi + 1} ({w[maxi]}, {p[maxi]}) completely in the bag. Space left: {cur_w}.") else: percent_added = int((1 + (cur_w / p[maxi])) * 100) print(f"Added {percent_added}% ({w[maxi]}, {p[maxi]}) of object {maxi + 1} in the bag.") tot_v -= w[maxi] tot_v += (1 + (cur_w / p[maxi])) * w[maxi] print(f"Filled the bag with objects worth {tot_v:.2f}.")
输出
Added object 5 (8, 1) completely in the bag. Space left: 9. Added object 2 (15, 3) completely in the bag. Space left: 6. Added object 3 (10, 2) completely in the bag. Space left: 4. Added object 1 (10, 3) completely in the bag. Space left: 1. Added 19% (12, 5) of object 4 in the bag. Filled the bag with objects worth 45.40.
应用领域
背包问题的许多实际应用中很少有 -
切割原材料而不损失太多材料
通过投资和投资组合进行挑选
资产证券化的资产选择
为 Merkle-Hellman 算法生成密钥
认知无线电网络
功率分配
移动节点的网络选择
协作无线通信