從「採藥」問題看0 1揹包

2021-08-15 17:20:44 字數 2615 閱讀 6167

(0/1揹包題目:對於每一件物品,只能取一次,而且有容量限制,每件物品有重量和價值,決策為取與不取)

講完了數塔問題,咱們再來看看乙個炒雞老炒雞老的題目:noip2005 pj組 第三題:「採藥」。

題目描述

對於這道題目,我們先來想想搜尋怎麼寫(因為dp和記搜很相似)。

我們先定義f[i][j]表示剩餘i時間,取了j株草藥所能獲得的最大價值。

那麼,冗餘搜尋是什麼?

讓我們來思考:如果在取到第x株草藥時花費了t時間,而且目前所獲得的價值比f[t][x]所要小,那麼接下來無論怎麼操作它最後得出的ans一定比用f[t][x]所進行操作的ans小?

答案就是如此(大家可以思考一下為什麼)。

接下來附上記搜**:

void dfs(int t, int x, int val) // 當前的狀態: 揹包還剩t的空間, 現在採到第x棵草藥, 目前的總價值為val

dfs(t, x+1, val); // 不取這一棵

if(t >= w[x]) dfs(t - w[x], x+1, val + v[x]); // 取這一棵, 前提是當前的空間足夠

}

寫完了記搜,然後我們來看看dp的實現方式

我們先來回顧一下動態規劃的意義:只記錄狀態的最優值,並用最優值來推導其他的最優值。

然後我們通過剛剛的記搜來設計我們的狀態:

f[i][j]表示:已經決定了前i株草藥,用了j的時間,所能得到的最大價值。

先來看順推:

>不取:狀態轉移為f[i+1][j]

>取:狀態轉移為f[i+1][j-w[i+1]](需要滿足重量約束)

再來看逆推:

「我這個狀態從何而來」:決定我這個物品取不取

>不取:由f[i-1][j]推導而來

>取:由f[i-1][j-w[i]]推導而來(需要滿足重量約束)

先附上順推**:

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

for(int j = 0; j <= t; ++ j)

ans = f[n][t]; // 答案

cout << ans << endl;

現在附上逆推**:

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

for(int j = 0; j <= t; ++ j)

ans = 0;

for(int i = 0; i <= t; ++ i) ans = max(ans, f[n][i]);

cout << ans << endl; // 輸出答案

接下來我們來考慮陣列壓縮:

*陣列壓縮:即用乙個一維陣列來代替二維陣列

-觀察方程,我們可以發現,f[i]僅僅是由f[i-1]決定的,也就是說,前面的大多數狀態對後面均無影響。

f[1]

......

......

......

f[2]

......

......

......

f[3]00

f[3][3]=12

0f[3][5]=15

0f[4]

f[4][1]=?

f[4][2]=?

f[4][3]=?

f[4][4]=?

f[4][5]=?

f[4][6]=?

f[5]

f[6]

如上表,f[4]中的所有狀態只和f[3]中的兩個狀態f[3][3]和f[3][5]有關而f[3][1],f[3][2]等等對於f[4]中的任意乙個值都沒有影響,所以我們可以僅僅保留前一行的狀態。

那如何壓縮呢?我們用一種特別簡單的方法:將j倒著列舉。

附上**:

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

for(int j = t; j >= 0; -- j) // 在使用壓縮狀態的時候, 需要注意列舉的方向

上述就是採藥的全部講解,實際上採藥是一道全裸的0/1揹包題目,對於所有全裸的0/1揹包,均可用上述的三種**來實現。

結束了?

沒有。實際上,對於0/1揹包的**打法。還有另外一種:

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

for(int j = t; j >= w[i]; -- j) // 在使用壓縮狀態的時候, 需要注意列舉的方向

有沒有發現什麼不一樣?

沒錯,第二層for迴圈,把「0」改為w[i],可以省掉乙個if判斷,是不是很厲(méi)害(yòng)?

好了,以上就是採藥及0/1揹包的全部講解。

採藥 01揹包問題

辰辰是個天資聰穎的孩子,他的夢想是成為世界上最偉大的醫師。為此,他想拜附近最有威望的醫師為師。醫師為了判斷他的資質,給他出了乙個難題。醫師把他帶到乙個到處都是草藥的山洞裡對他說 孩子,這個山洞裡有一些不同的草藥,採每一株都需要一些時間,每一株也有它自身的價值。我會給你一段時間,在這段時間裡,你可以採...

採藥 01揹包

from silence 採藥 背景 background noip2005複賽普及組第三題 描述 description 辰辰是個天資聰穎的孩子,他的夢想是成為世界上最偉大的醫師。為此,他想拜附近最有威望的醫師為師。醫師為了判斷他的資質,給他出了乙個難題。醫師把他帶到乙個到處都是草藥的山洞裡對他說...

採藥(0 1揹包)

題目描述 辰辰是個天資聰穎的孩子,他的夢想是成為世界上最偉大的醫師。為此,他想拜附近最有威望的醫師為師。醫師為了判斷他的資質,給他出了乙個難題。醫師把他帶到乙個到處都是草藥的山洞裡對他說 孩子,這個山洞裡有一些不同的草藥,採每一株都需要一些時間,每一株也有它自身的價值。我會給你一段時間,在這段時間裡...