動(dòng)態(tài)規(guī)劃——01背包問題

</br> <a>背包問題(Knapsack problem)</a>是一種組合優(yōu)化的NP完全問題。問題可以描述為:給定一組物品,每種物品都有自己的重量和價(jià)格,在限定的總重量?jī)?nèi),我們?nèi)绾芜x擇,才能使得物品的總價(jià)格最高。
01背包問題就是背包問題中最經(jīng)典的題目之一,常被程序設(shè)計(jì)競(jìng)賽選為母題,是每個(gè)選手必須掌握的重要知識(shí)點(diǎn)。
</br>

<a>01背包問題</a>

<pre></br>有n個(gè)質(zhì)量和價(jià)值分別為w1,vi的物品。從這些物品中挑選出總質(zhì)量不超過W的物品,求所有挑選方案中價(jià)值總和的最大值</br></pre>

<a>解題思路</a>

首先嘗試用最樸素的方法:枚舉每一種可能來比較最大值。

所以,第一步,運(yùn)用動(dòng)態(tài)規(guī)劃的思想列出本題的動(dòng)規(guī)方程:

1.設(shè) f (i , j) 為計(jì)算從i到n這n-i個(gè)物品質(zhì)量總和不大于j的價(jià)值最大值。

2.那么對(duì)于每一個(gè)物品,都有取或不取兩種狀態(tài),所以很快就可以列出遞歸方程:<pre>f (i, j) = max{f(i + 1, j - w[i]) + v[i], //取此物品</br> f(i + 1, j)} //不取此物品</pre>

3.So,就可以據(jù)此寫出遞歸代碼
<pre>
<code>#define MAXN 1000</code>
<code>
int n, W;//物品總數(shù)和最大質(zhì)量
int w[MAXN+1], v[MAXN+1];//物品質(zhì)量和價(jià)值

int f(int i, int j)//前i個(gè)物品,價(jià)格不超過j的最大值
{
int ret;
if (i >= n)//沒有多余物品了
return 0;
if (v[i] > j)//要求質(zhì)量不夠拿此物品
ret = f(i+1, j);
else
//比較那或不拿那個(gè)價(jià)值大
ret = max(f(i+1, j-v[i])+(v[i]*w[i]), f(i+1, j));
return ret;
}
</code></pre>
但是,如果你對(duì)時(shí)間復(fù)雜度有一些了解,就很快會(huì)發(fā)現(xiàn)一個(gè)問題:</br>如果這樣寫代碼,時(shí)間復(fù)雜度就是O(2^n)。明顯會(huì)超出時(shí)間限制。[關(guān)于時(shí)間復(fù)雜度可以到http://blog.csdn.net/flyyyri/article/details/5154618做一下了解]
</br></br>
所以,再次利用動(dòng)態(tài)規(guī)劃的重要思想:記憶化搜索,來優(yōu)化算法:
<pre>
<code>#define MAXN 1000</code>
<code>
int n, W;//物品總數(shù)和最大質(zhì)量
int w[MAXN+1], v[MAXN+1];//物品質(zhì)量和價(jià)值
int dpmem[MAXN+1][MAXN+1];//記憶數(shù)組

int f(int i, int j)//前i個(gè)物品,價(jià)格不超過j的最大值
{
int ret;
if(dpmem[i][j] != -1)//是否已經(jīng)計(jì)算過此結(jié)果
return dpmem[i][j];//返回已計(jì)算結(jié)果
if (i >= n)//沒有多余物品了
return 0;
if (v[i] > j)//要求質(zhì)量不夠拿此物品
ret = f(i+1, j);
else
//比較那或不拿那個(gè)價(jià)值大
ret = max(f(i+1, j-v[i])+(v[i]*w[i]), f(i+1, j));
dpmem[i][j] = ret;//記錄結(jié)果
return ret;
}
</code></pre>需要注意的是,在使用前,需要對(duì)dpmem數(shù)組初始化(我這里是全初始化成-1來代表還未計(jì)算),可以用memset實(shí)現(xiàn)。

順便附一組測(cè)試數(shù)據(jù)以供參考:

測(cè)試數(shù)據(jù):
n = 4, m = 10
w[i] = {2, 3, 2, 1};
v[i] = {4, 8, 10, 5};

結(jié)果:
27

引用:
1.百度百科
2.《挑戰(zhàn)程序設(shè)計(jì)競(jìng)賽》

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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