hiho一下 第六周 Hihocoder #1038 : 01背包
題目1 : 01背包
時間限制:20000ms 單點時限:1000ms 內存限制:256MB描述
且說上一周的故事里,小Hi和小Ho費勁心思終于拿到了茫茫多的獎券!而現在,終于到了小Ho領取獎勵的時刻了!
小Ho現在手上有M張獎券,而獎品區有N件獎品,分別標號為1到N,其中第i件獎品需要need(i)張獎券進行兌換,同時也只能兌換一次,為了使得辛苦得到的獎券不白白浪費,小Ho給每件獎品都評了分,其中第i件獎品的評分值為value(i),表示他對這件獎品的喜好值。現在他想知道,憑借他手上的這些獎券,可以換到哪些獎品,使得這些獎品的喜好值之和能夠最大。
小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{best(N - 1, M - need(N)) + value(N), best(N - 1, M)}!”
“沒錯!”小Ho道:“同樣的道理,對于任意i>1, j,我們都可以知道best(i, j)=max{best(i-1, j-need(i)) + value(i), best(i - 1, j)}!”
“歸納的不錯!那么你接檢驗一下這個問題的定義方法是否擁有動態規劃所需要的兩種性質?”
小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-1, j-need(i)) + value(i), best(i - 1, j)}來求解每一個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開心道。
“那你還不去寫?”
輸入
每個測試點(輸入文件)有且僅有一組測試數據。
每組測試數據的第一行為兩個正整數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可以獲得的總喜好值。
樣例輸入總結
以上是生活随笔為你收集整理的hiho一下 第六周 Hihocoder #1038 : 01背包的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: hiho一下 第五周 Hihocoder
- 下一篇: hiho一下 第七周 Hihocoder