W3Cschool
恭喜您成為首批注冊用戶
獲得88經驗值獎勵
Question
給定
圖 15-3 分數(shù)背包問題的示例數(shù)據(jù)
分數(shù)背包和 0-1 背包整體上非常相似,狀態(tài)包含當前物品
不同點在于,本題允許只選擇物品的一部分。如圖 15-4 所示,我們可以對物品任意地進行切分,并按照重量比例來計算物品價值。
圖 15-4 物品在單位重量下的價值
最大化背包內物品總價值,本質上是要最大化單位重量下的物品價值。由此便可推出圖 15-5 所示的貪心策略。
圖 15-5 分數(shù)背包的貪心策略
我們建立了一個物品類 Item
,以便將物品按照單位價值進行排序。循環(huán)進行貪心選擇,當背包已滿時跳出并返回解。
fractional_knapsack.cpp
/* 物品 */
class Item {
public:
int w; // 物品重量
int v; // 物品價值
Item(int w, int v) : w(w), v(v) {
}
};
/* 分數(shù)背包:貪心 */
double fractionalKnapsack(vector<int> &wgt, vector<int> &val, int cap) {
// 創(chuàng)建物品列表,包含兩個屬性:重量、價值
vector<Item> items;
for (int i = 0; i < wgt.size(); i++) {
items.push_back(Item(wgt[i], val[i]));
}
// 按照單位價值 item.v / item.w 從高到低進行排序
sort(items.begin(), items.end(), [](Item &a, Item &b) { return (double)a.v / a.w > (double)b.v / b.w; });
// 循環(huán)貪心選擇
double res = 0;
for (auto &item : items) {
if (item.w <= cap) {
// 若剩余容量充足,則將當前物品整個裝進背包
res += item.v;
cap -= item.w;
} else {
// 若剩余容量不足,則將當前物品的一部分裝進背包
res += (double)item.v / item.w * cap;
// 已無剩余容量,因此跳出循環(huán)
break;
}
}
return res;
}
最差情況下,需要遍歷整個物品列表,因此時間復雜度為
由于初始化了一個 Item
對象列表,因此空間復雜度為
采用反證法。假設物品 res
,但該解中不包含物品
現(xiàn)在從背包中拿出單位重量的任意物品,并替換為單位重量的物品 res
。這與 res
是最優(yōu)解矛盾,說明最優(yōu)解中必須包含物品
對于該解中的其他物品,我們也可以構建出上述矛盾。總而言之,單位價值更大的物品總是更優(yōu)選擇,這說明貪心策略是有效的。
如圖 15-6 所示,如果將物品重量和物品單位價值分別看作一個 2D 圖表的橫軸和縱軸,則分數(shù)背包問題可被轉化為“求在有限橫軸區(qū)間下的最大圍成面積”。這個類比可以幫助我們從幾何角度理解貪心策略的有效性。
圖 15-6 分數(shù)背包問題的幾何表示
Copyright©2021 w3cschool編程獅|閩ICP備15016281號-3|閩公網安備35020302033924號
違法和不良信息舉報電話:173-0602-2364|舉報郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號
聯(lián)系方式:
更多建議: