1. 程式人生 > >POJ-3624-揹包問題

POJ-3624-揹包問題

它這個問題問的是,在有限的容量下,能裝下的最大價值是多少。

所以我們可以遞迴求解,記憶性遞迴,用二維陣列,但是這樣的話就會超記憶體,所以我們只能用動規來寫,而且不能開二維陣列,

只能用滾動陣列。

我們設一個F陣列,大小為13000,它存的是容積為m的揹包可放下的最大價值。

我們先假設一個二維陣列F [ i ][ j ] ,它表示的意思是,揹包裡放 i 個物品,最大價值為 j ,它的最大價值。

我們可以知道 F [ i ][ j ] = max ( F [ i-1][ j ] ,F[ i-1][ j-w[i] ] +value [ i ] ) 。

它的意思是,F [ i ][ j ]的值來自於如果不選第 i 個物品,放下值為 j 的包的最大價值,和如果選第 i 個物品,揹包裡放下 j-weight[i] 大小物品的最大價值和第 i 個物品價值之和,經過比較之後最大的那個值。

我們對於F [ i ][ j ]可以選也可以不選,不選的話,它的價值就是F [ i-1 ][ j ] ,選的話它的價值就是F[ i-1][ j-w[i] ] +value [ i ] ,就是在原揹包容積減去 i 物品的重量之後,放入 i-1 個物品的最大價值與 i 物品的價值之和。

不過有個條件,如果 j-w[i] >=0 ,我們才比較求解,小於它的話,我們就讓它等於它的上一行同列的值。

好,那麼問題來了,這個問題怎麼在一維陣列中求解呢?

首先我們要知道,在二維數組裡面它們的形態:

                                            F[ i-1][ j-w[i] ]                   F [ i-1][ j ]

                                                                                    F [ i ][ j ]                                F[ i ][ 2j-w[i] ]

所以說,對於F [ i-1 ][ j ] ,我們還是有用的,我們要用來求右下角的那個元素,我們不能正向,由小到大直接把F [ i-1 ][ j ]覆蓋掉,我們應該在用完它時候,再覆蓋掉,所以我們從右向左求,就不會傷害任何值了。

程式碼如下:

#include <iostream>
using namespace std;
int w[3600],d[3600],F[13000];
int main()
{
	int n,m;
	cin>>n>>m;
	for (int i=1;i<=n;i++) {
		cin>>w[i]>>d[i];
	}
	for (int i=1;i<=n;i++) {
		for (int j=m;j>=w[i];j--) {
			F[j]=max(F[j],F[j-w[i]]+d[i]);
		}
	}
	cout<<F[m]<<endl;
	return 0;
 }