完全背包

2.1 題目

有 N 種物品和一個容量為 V 的背包,每種物品都有無限件可用。放入第 i 種物品
的費用是 C i ,價值是 W i 此再。求解:將哪些物品裝入背包,可使這些物品的耗費的費用總
和不超過背包容量,且價值總和最大。

2.2 基本思路

這個問題非常類似于 01 背包問題,所不同的是每種物品有無限件摘符。也就是從每種
物品的角度考慮,與它相關(guān)的策略已并非取或不取兩種,而是有取 0 件策吠、取 1 件、取 2
件......直至取 ?V /C i ? 件等許多種带族。
  如果仍然按照解 01 背包時的思路,令 F [i, v] 表示前 i 種物品恰放入一個容量為 v
的背包的最大權(quán)值蟀给。仍然可以按照每種物品不同的策略寫出狀態(tài)轉(zhuǎn)移方程,像這樣:

F [i, v] = max{F [i ? 1, v ? kCi ] + kWi | 0 ≤ kCi ≤ v}

寒冰王座

#include <cstdio>
#include<algorithm>
#include<string.h>
#define Max(a,b) a>b?a:b
using namespace std;
int main()
{
    int t;
    int dp[4][10010],val[4]={0,150,200,350},vom[4]={0,150,200,350};
    scanf("%d",&t);
  while(t--)
  {
        int v;
        scanf("%d",&v);
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=3;i++)
        {
            for(int j=0;j<=v;j++)//v必須升序
            {
                for(int k=v/vom[i];k>=0;k--)//k必須降序
                {
                    if(j-k*vom[i]>=0)
                    dp[i][j]=Max(dp[i-1][j],dp[i][j-k*vom[i]]+k*val[i]);
                    else dp[i][j]=dp[i-1][j];
                }
            }
        }
        printf("%d\n",v-dp[3][v]);
  }
}

這跟 01 背包問題一樣有 O(VN ) 個狀態(tài)需要求解,但求解每個狀態(tài)的時間已經(jīng)不
是常數(shù)了,求解狀態(tài) F [i, v] 的時間是 O( C Vi ) ,總的復(fù)雜度可以認(rèn)為是 O(NV ΣV/Ci ) ,是
比較大的。
  將 01 背包問題的基本思路加以改進,得到了這樣一個清晰的方法择克。這說明 01 背包
問題的方程的確是很重要,可以推及其它類型的背包問題。但我們還是要試圖改進這個
復(fù)雜度壹堰。

2.4 轉(zhuǎn)化為 01 背包問題求解

01 背包問題是最基本的背包問題,我們可以考慮把完全背包問題轉(zhuǎn)化為 01 背包問
題來解骡湖。
  最簡單的想法是,考慮到第 i 種物品最多選 ?V /Ci ? 件,于是可以把第 i 種物品轉(zhuǎn)
化為 ?V /Ci ? 件費用及價值均不變的物品,然后求解這個 01 背包問題。這樣的做法完
全沒有改進時間復(fù)雜度,但這種方法也指明了將完全背包問題轉(zhuǎn)化為 01 背包問題的思
路:將一種物品拆成多件只能選 0 件或 1 件的 01 背包中的物品谆焊。
  更高效的轉(zhuǎn)化方法是:把第 i 種物品拆成費用為 Ci*2^k 换途、價值為 Wi*2^k 的若干件物
品,其中 k 取遍滿足 Ci*2^k ≤ V 的非負(fù)整數(shù)。
  這是二進制的思想剃执。因為,不管最優(yōu)策略選幾件第 i 種物品,其件數(shù)寫成二進制后,
總可以表示成若干個 2^k 件物品的和懈息。這樣一來就把每種物品拆成 O(log ?V /Ci ?) 件物
品,是一個很大的改進。

2.5 O(V N ) 的算法

這個算法使用一維數(shù)組,先看偽代碼:

F [0..V ] ←0
 for i ← 1 to N
  for v ← C i to V
   F [v] ← max(F [v], F [v ? Ci ] + W i )

你會發(fā)現(xiàn),這個偽代碼與 01 背包問題的偽代碼只有 v 的循環(huán)次序不同而已怒见。
  為什么這個算法就可行呢?首先想想為什么 01 背包中要按照 v 遞減的次序來循環(huán)姑宽。
讓 v 遞減是為了保證第 i 次循環(huán)中的狀態(tài) F [i, v] 是由狀態(tài) F [i ? 1, v ? Ci ] 遞推而來。
換句話說,這正是為了保證每件物品只選一次,保證在考慮“選入第 i 件物品”這件策略時,依據(jù)的是一個絕無已經(jīng)選入第 i 件物品的子結(jié)果 F [i ? 1, v ? Ci ] 舵变。而現(xiàn)在完全背包的特點恰是每種物品可選無限件,所以在考慮“加選一件第 i 種物品”這種策略時,卻正需要一個可能已選入第 i 種物品的子結(jié)果 F [i, v ? Ci ] ,所以就可以并且必須采用 v遞增的順序循環(huán)瘦穆。這就是這個簡單的程序為何成立的道理。
  值得一提的是,上面的偽代碼中兩層 for 循環(huán)的次序可以顛倒绵咱。這個結(jié)論有可能會帶來算法時間常數(shù)上的優(yōu)化熙兔。
  這個算法也可以由另外的思路得出艾恼。例如,將基本思路中求解 F [i, v ? Ci ] 的狀態(tài)轉(zhuǎn)移方程顯式地寫出來,代入原方程中,會發(fā)現(xiàn)該方程可以等價地變形成這種形式:

F [i, v] = max(F [i ? 1, v], F [i, v ? Ci ] + Wi )

2.6 小結(jié)

完全背包問題也是一個相當(dāng)基礎(chǔ)的背包問題,它有兩個狀態(tài)轉(zhuǎn)移方程拢切。希望讀者能
夠?qū)@兩個狀態(tài)轉(zhuǎn)移方程都仔細(xì)地體會,不僅記住,也要弄明白它們是怎么得出來的,
最好能夠自己想一種得到這些方程的方法秆吵。
  事實上,對每一道動態(tài)規(guī)劃題目都思考其方程的意義以及如何得來,是加深對動態(tài)
規(guī)劃的理解、提高動態(tài)規(guī)劃功力的好方法主穗。
寒冰王座

#include <cstdio>
#include<algorithm>
#include<string.h>
#define Max(a,b) a>b?a:b
using namespace std;
int main()
{
    int t;
    int dp[10010],val[4]={0,150,200,350},vom[4]={0,150,200,350};
    scanf("%d",&t);
  while(t--)
  {
        int v;
        scanf("%d",&v);
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=3;i++)
        {
            for(int j=vom[i];j<=v;j++)
            {
                dp[j]=Max(dp[j],dp[j-vom[i]]+val[i]);
            }
        }
        printf("%d\n",v-dp[v]);
  }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末忽媒,一起剝皮案震驚了整個濱河市腋粥,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌闹瞧,老刑警劉巖展辞,帶你破解...
    沈念sama閱讀 221,635評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異洽腺,居然都是意外死亡覆旱,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評論 3 399
  • 文/潘曉璐 我一進店門藕坯,熙熙樓的掌柜王于貴愁眉苦臉地迎上來画舌,“玉大人,你說我怎么就攤上這事霹购∨笠福” “怎么了膜楷?”我有些...
    開封第一講書人閱讀 168,083評論 0 360
  • 文/不壞的土叔 我叫張陵贞奋,是天一觀的道長。 經(jīng)常有香客問我特愿,道長勾缭,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,640評論 1 296
  • 正文 為了忘掉前任毒嫡,我火速辦了婚禮幻梯,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘咬摇。我一直安慰自己,他們只是感情好菲嘴,可當(dāng)我...
    茶點故事閱讀 68,640評論 6 397
  • 文/花漫 我一把揭開白布龄坪。 她就那樣靜靜地躺著复唤,像睡著了一般。 火紅的嫁衣襯著肌膚如雪佛纫。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,262評論 1 308
  • 那天好爬,我揣著相機與錄音甥啄,去河邊找鬼。 笑死穆桂,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的享完。 我是一名探鬼主播,決...
    沈念sama閱讀 40,833評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼彼绷,長吁一口氣:“原來是場噩夢啊……” “哼苛预!你這毒婦竟也來了笋熬?” 一聲冷哼從身側(cè)響起腻菇,我...
    開封第一講書人閱讀 39,736評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎糖耸,沒想到半個月后丘薛,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,280評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡舍扰,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,369評論 3 340
  • 正文 我和宋清朗相戀三年希坚,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片个束。...
    茶點故事閱讀 40,503評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡聊疲,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出阱表,到底是詐尸還是另有隱情,我是刑警寧澤捶枢,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布烂叔,位于F島的核電站,受9級特大地震影響蒜鸡,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜叶沛,卻給世界環(huán)境...
    茶點故事閱讀 41,870評論 3 333
  • 文/蒙蒙 一忘朝、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧溉箕,春花似錦悦昵、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,340評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽拦坠。三九已至贫橙,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間卢肃,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,460評論 1 272
  • 我被黑心中介騙來泰國打工尤蒿, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留幅垮,地道東北人。 一個月前我還...
    沈念sama閱讀 48,909評論 3 376
  • 正文 我出身青樓示弓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親跨跨。 傳聞我的和親對象是個殘疾皇子囱皿,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,512評論 2 359

推薦閱讀更多精彩內(nèi)容