
- 資料結構與演算法
- DSA - 首頁
- DSA - 概述
- DSA - 環境設定
- DSA - 演算法基礎
- DSA - 漸進分析
- 資料結構
- DSA - 資料結構基礎
- DSA - 資料結構和型別
- DSA - 陣列資料結構
- 連結串列
- DSA - 連結串列資料結構
- DSA - 雙向連結串列資料結構
- DSA - 迴圈連結串列資料結構
- 棧與佇列
- DSA - 棧資料結構
- DSA - 表示式解析
- DSA - 佇列資料結構
- 搜尋演算法
- DSA - 搜尋演算法
- DSA - 線性搜尋演算法
- DSA - 二分搜尋演算法
- DSA - 插值搜尋
- DSA - 跳躍搜尋演算法
- DSA - 指數搜尋
- DSA - 斐波那契搜尋
- DSA - 子列表搜尋
- DSA - 雜湊表
- 排序演算法
- DSA - 排序演算法
- DSA - 氣泡排序演算法
- DSA - 插入排序演算法
- DSA - 選擇排序演算法
- DSA - 歸併排序演算法
- DSA - 希爾排序演算法
- DSA - 堆排序
- DSA - 桶排序演算法
- DSA - 計數排序演算法
- DSA - 基數排序演算法
- DSA - 快速排序演算法
- 圖資料結構
- DSA - 圖資料結構
- DSA - 深度優先遍歷
- DSA - 廣度優先遍歷
- DSA - 生成樹
- 樹資料結構
- DSA - 樹資料結構
- DSA - 樹的遍歷
- DSA - 二叉搜尋樹
- DSA - AVL樹
- DSA - 紅黑樹
- DSA - B樹
- DSA - B+樹
- DSA - 伸展樹
- DSA - 字典樹
- DSA - 堆資料結構
- 遞迴
- DSA - 遞迴演算法
- DSA - 使用遞迴實現漢諾塔問題
- DSA - 使用遞迴實現斐波那契數列
- 分治法
- DSA - 分治法
- DSA - 最大最小值問題
- DSA - Strassen矩陣乘法
- DSA - Karatsuba演算法
- 貪心演算法
- DSA - 貪心演算法
- DSA - 旅行商問題(貪心演算法)
- DSA - Prim最小生成樹演算法
- DSA - Kruskal最小生成樹演算法
- DSA - Dijkstra最短路徑演算法
- DSA - 地圖著色演算法
- DSA - 分數揹包問題
- DSA - 帶截止日期的作業排序
- DSA - 最佳合併模式演算法
- 動態規劃
- DSA - 動態規劃
- DSA - 矩陣鏈乘法
- DSA - Floyd-Warshall演算法
- DSA - 0-1揹包問題
- DSA - 最長公共子序列演算法
- DSA - 旅行商問題(動態規劃)
- 近似演算法
- DSA - 近似演算法
- DSA - 頂點覆蓋演算法
- DSA - 集合覆蓋問題
- DSA - 旅行商問題(近似演算法)
- 隨機演算法
- DSA - 隨機演算法
- DSA - 隨機快速排序演算法
- DSA - Karger最小割演算法
- DSA - Fisher-Yates洗牌演算法
- DSA有用資源
- DSA - 問答
- DSA - 快速指南
- DSA - 有用資源
- DSA - 討論
分數揹包問題
揹包問題陳述如下:給定一組物品,包含重量和利潤值,必須確定要新增到揹包中的物品子集,以便物品的總重量不超過揹包的限制,並且其總利潤值最大。
這是最流行的問題之一,它採用貪心演算法來解決。它被稱為**分數揹包問題**。
為了更容易解釋這個問題,請考慮一個包含12個問題,每個問題10分的測試,其中只有10個問題需要解答才能獲得100分的最高分。現在,測試者必須計算最有價值的問題——他最有把握的問題——以獲得最高分。但是,他不能嘗試所有12個問題,因為嘗試回答的答案不會獲得額外的分數。這是揹包問題最基本、最現實的應用之一。
揹包演算法
要新增到揹包中的物品的重量(Wi)和利潤值(Pi)作為分數揹包演算法的輸入,而新增到揹包中的物品子集(不超過限制且利潤最大)作為輸出。
演算法
考慮所有物品及其各自的重量和利潤。
計算所有物品的Pi/Wi,並根據它們的Pi/Wi值按降序對物品進行排序。
在不超過限制的情況下,將物品新增到揹包中。
如果揹包仍然可以存放一些重量,但其他物品的重量超過了限制,則可以新增下一個物品的分數部分。
因此,將其命名為分數揹包問題。
示例
對於給定的物品集和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}
計算所有物品的Pi/Wi
物品 | 1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|---|
重量(公斤) | 3 | 3 | 2 | 5 | 1 |
利潤 | 10 | 15 | 10 | 20 | 8 |
Pi/Wi | 3.3 | 5 | 5 | 4 | 8 |
步驟2
根據Pi/Wi按降序排列所有物品。
物品 | 5 | 2 | 3 | 4 | 1 |
---|---|---|---|---|---|
重量(公斤) | 1 | 3 | 2 | 5 | 3 |
利潤 | 8 | 15 | 10 | 20 | 10 |
Pi/Wi | 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演算法的金鑰
認知無線電網路
功率分配
移動節點網路選擇
協作無線通訊