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