01揹包 hihocoder第六周

2022-08-21 08:18:10 字數 4437 閱讀 7165

01揹包

且說上一周的故事裡,小hi和小ho費勁心思終於拿到了茫茫多的獎券!而現在,終於到了小ho領取獎勵的時刻了!

小ho現在手上有m張獎券,而獎品區有n件獎品,分別標號為1到n,其中第i件獎品需要need(i)張獎券進行兌換,同時也只能兌換一次,為了使得辛苦得到的獎券不白白浪費,小ho給每件獎品都評了分,其中第i件獎品的評分值為value(i),表示他對這件獎品的喜好值。現在他想知道,憑藉他手上的這些獎券,可以換到哪些獎品,使得這些獎品的喜好值之和能夠最大。

提示一:合理抽象問題、定義狀態是動態規劃最關鍵的一步

提示二:說過了減少時間消耗,我們再來看看如何減少空間消耗

輸入每個測試點(輸入檔案)有且僅有一組測試資料。

每組測試資料的第一行為兩個正整數n和m,表示獎品的個數,以及小ho手中的獎券數。

接下來的n行描述每一行描述乙個獎品,其中第i行為兩個整數need(i)和value(i),意義如前文所述。

測試資料保證

對於100%的資料,n的值不超過500,m的值不超過10^5

對於100%的資料,need(i)不超過2*10^5, value(i)不超過10^3

輸出對於每組測試資料,輸出乙個整數ans,表示小ho可以獲得的總喜好值。

樣例輸入

5 1000

144 990

487 436

210 673

567 58

1056 897

樣例輸出

下面是hihocoder給出的解析,挺詳細的

提示一:合理抽象問題、定義狀態是動態規劃最關鍵的一步

小hi想了想,問道:「你打算怎麼做?」

「列舉2^n種可能的選取方案,先計算他們需要的獎券之和sum,在sum不超過m的情況下,計算他們的喜好值之和value,並統計乙個最優的方案,也就是value的最大值!」天真的小ho給出了乙個同樣天真的方案。

「簡直白教你動態規劃了……」小hi不禁扶額道:「這道題目你還是考慮一下如何使用動態規劃來解決吧!」

「好的!讓我回憶一下……動態規劃要求問題存在兩種性質:重複子問題和無後效性~但是...我怎麼也看不出這道題目怎麼套上這兩種性質呀,什麼樣算是乙個子問題?」小ho想了想,說道。

「先別急,你想要知道子問題是什麼?那麼首先,我們要想辦法把我們現在遇到的問題給抽象化!」

小ho低頭思索了一會,說道:「唔,我想想,如果用best(x)表示手中有x張獎券時能夠獲取的最高的喜好值的和,那麼我們的問題就是best(m)是多少?」

「你這樣定義的話,是沒有辦法把『求解best(m)』這樣乙個問題分解成不同的子問題的哦~」小hi笑道:「也罷,初學者往往都很難自己想出如何好的抽象問題,這次就讓我先來告訴你~」

「就知道賣關子~快說!」

小hi笑了笑,繼續說道:「這個問題——best(m)的求解,其實問的便是每個獎品是否選擇是麼?那麼你在遍歷這2^n種可能的選取方案的時候,是不是按照順序,一一確定每乙個獎品是否選取?」

「是的!」

小hi繼續道:「那麼我們不妨就按照你遍歷時的情況來,不過做一點小改動,以best(i, x)表示已經決定了前i件物品是否選取,當前已經選取的物品的所需獎券數總和不超過x時,能夠獲取的最高的喜好值的和。」

「聽起來的確和搜尋很像,搜尋時就是按照編號從小到大的順序一一決定每件物品是否選取,並且維護乙個當前已經選取的物品的所需獎券書的總和。」忽然小ho似乎想到了什麼:「誒,那麼這個best(i, x)其實就是和之前遇到的數字三角形迷宮問題中用於解決問題的記憶化搜尋很相似的?」

「沒錯,記憶化搜尋的確就是和動態規劃極為相似,或者可以說,他們用以解決問題的原理是一樣的。」小hi回答道。

「原來如此,我想想……那麼最終的答案其實就是best(n, m)是麼?」小ho得出了結論。

「是的!這個時候我們就可以稱best(n, m)的求解為我們的問題了!」小hi高興道。

「那麼子問題呢?」

小hi揮了揮手示意小ho不要著急:「子問題通常會採取將問題分成若干部分來進行,有的時候是均分,也有的時候僅僅是在規模上減一。比如這裡,我們不妨考慮best(n, m)這個問題的最後乙個決策——第n件獎品是否進行選擇:首先,如果選擇第n件獎品,當然首先要保證第n件商品所需的獎券數不超過m,我們可以知道這種方案的最佳收益為best(n - 1, m - need(n)) + value(n)。」

「其次呢,如果不選擇第n件獎品,我們可以知道這種方案的最佳收益為best(n - 1, m)。」小hi頓了頓,繼續道:」由於第n件獎品只有選取和不選取兩種可能,我們於是可以知道best(n, m) = max!」

「沒錯!」小ho道:「同樣的道理,對於任意i>1, j,我們都可以知道best(i, j)=max!」

「歸納的不錯!那麼你接檢驗一下這個問題的定義方法是否擁有動態規劃所需要的兩種性質?」

小ho想了想,決定一條一條的來:「首先看重複子問題——這是動態規劃之所以比搜尋高效的原因,如果最後四件獎品分別為所需獎券為1,喜好值為1、所需獎券為2,喜好值為2、所需獎券為3,喜好值為3、所需獎券為4,喜好值為4的四個獎品,那麼無論是選擇1、4還是2、3,都會要求解best(n-4, m-5)這樣乙個子問題,而這個子問題只需要求解一次就能夠進行計算,所以重複子問題這一性質是滿足的。」

「沒錯,接著說。」

「其次再看無後效性……同樣的,如果分別有所需獎券為1,喜好值為1、所需獎券為2,喜好值為2、所需獎券為3,喜好值為3、所需獎券為4,喜好值為4的四個獎品,那麼無論是選取第1個和第4個,還是選取第2個和第3個,他們的所需獎券數都為5,喜好值之和都為5。所以我只需要知道best(4, 5)=5就夠了,它為什麼等於5對我而言沒有區別,不會對之後的決策產生影響。這就是無後效性,所以想來也是滿足的。

「說的挺正確~那麼接下來要考慮的是如何使用best(i, j)=max來求解每乙個best(i, j)了~」小hi道:「這部分我便直接告訴你吧,我們定義乙個問題a依賴於另乙個問題b當且僅當求解a的過程中需要事先知道b的值,那麼我們很容易的發現best(i, j)是依賴於best(i-1, j-need(i))和best(i-1,

j)兩個問題的,也就是說這兩個問題要先於best(i, j)進行求解~」

「所以我們只要按照i從小到大的順序,以這樣的方式進行計算,就可以了!」小ho插嘴道。

「你又搶我台詞!」

提示二:說過了減少時間消耗,我們再來看看如何減少空間消耗

且說小ho搞清楚了計算方法,正在埋頭苦寫**,在一旁看他寫**的小hi是在看不下去了,決定再指點指點小ho:「小ho啊!」

「怎麼了?」小ho眼睛盯著螢幕,望都沒望小hi一眼。

「你現在是不是需要開乙個n * m大小的二維陣列best,來記錄求解出的best值呀?」

小ho終於有了點反應,抬起頭來說道:「是啊,怎麼了?「

「我有辦法不用開這麼大空間哦~」小hi笑嘻嘻道:」可我就是不告訴你!」

「誒,別這樣,我請你吃雪糕!」小ho一聽就急了,連忙許下了報酬。

「開玩笑啦~」小hi也是隨便逗了逗樂子就沒繼續:「你想想,在i已經是10以上的時候,best(5, j)這樣的值還有用麼?」

「沒有用了……你是說,我並不需要在記憶體中存下來所有的best(i, j),沒有用了的值都可以不進行儲存……也就是說,實際上只要開乙個2*m大小的陣列就可以了,然後像這樣的方式進行來回的計算,是不是就可以了?」

「是的呢!但是還可以更少哦~讓我來寫這個程式的話,我只需要開乙個m大小的一維陣列就可以了」小hi自信的說道:「你想想,如果我按照j從m到1的順序,也就是跟之前相反的順序來進行計算的話。另外根據我們的狀態轉移方程,可以顯然得出如果狀態(ia, ja)依賴於狀態(ib, jb),那麼肯定有ia = ib+1, ja>=jb。所以不難得出乙個結論:我在計算best(i, j)的時候,因為best(i, j+1..m)這些狀態已經被計算過了,所以意味著best(i

- 1, k),k=j..m這些值都沒有用了——所有依賴於他們的值都已經計算完了。於是它們原有的儲存空間都可以用來儲存別的東西,所以我不仿直接就將best(i, j)的值存在best(i-1, j)原有的位置上,就像這樣。」

「原來還可以這樣!這樣一處理,不僅空間複雜度小了很多,**也很好看了呢!」小ho開心道。

「那你還不去寫?

**:

#include#include#include#includeusing namespace std;

int dp[100005],v[505],need[505];

int main()

for(int i=1;i<=m;i++) dp[i]=0;

for(int i=1;i<=n;i++)

}printf("%d\n",dp[m]);

return 0;

}

hihocoder 完全揹包

小ho現在手上有m張獎券,而獎品區有n種獎品,分別標號為1到n,其中第i種獎品需要need i 張獎券進行兌換,並且可以兌換無數次,為了使得辛苦得到的獎券不白白浪費,小ho給每件獎品都評了分,其中第i件獎品的評分值為value i 表示他對這件獎品的喜好值。現在他想知道,憑藉他手上的這些獎券,可以換...

揹包 01揹包

01揹包 有n種物品與承重為m的揹包。每種物品只有一件,每個物品都有對應的重量weight i 與價值value i 求解如何裝包使得價值最大。dp i,v 表示前i個物體 包括第i個 面對容量為v的揹包的最大價值,c i 代表物體i的重量,w i 代表物體i的價值 如果第i個物體不放入揹包,則揹包...

揹包專題 01揹包

暑假集訓開始了,按照隊裡的分配,我是弄dp的,嘛,於是我又一次的開始了從01揹包開始學習,昨天將杭電的幾道01揹包重新做了一遍,下面講講我自己對於01揹包的理解。首先01揹包題目的雛形是 有n件物品和乙個容量為v的揹包。第i件物品的費用是c i 價值是w i 求解將哪些物品裝入揹包可使價值總和最大。...