分組揹包問題解法

前面的博客中提到了0/1揹包問題,下面說明一種更加複雜的動態規劃問題——分組揹包。

一個容量爲V的揹包有N(0,1,2……i……N)件物品。第i件物品的費用是c[i],價值是w[i]。這些物品被劃分爲若干組,每組中的物品互相沖突,最多選一件。求解將哪些物品裝入揹包可使這些物品的費用總和不超過揹包容量,且價值總和最大。
這個問題變成了每組物品有若干種策略:是選擇本組的某一件,還是一件都不選。設f[k][v]表示前k組物品花費費用v能取得的最大權值,則有:
f[k][v]=max{f[k-1][v],f[k-1][v-c[i]]+w[i]|物品i屬於組k}
使用一維數組的僞代碼如下:
for 所有的組k
    for v=V..0  #花費從V到零,爲防止重複選擇同一組中的多個物品
        for 所有的i屬於組k
            f[v]=max{f[v],f[v-c[i]]+w[i]}

最後的f[v]即爲所求。

下面介紹一種使用分組揹包的一個實例:分組揹包給定 n 和 k。計算有多少長度爲 k 的數組 a1, a2, ..., ak,(0≤ai) 滿足:

  a1 + a2 + ... + ak = n。
對於任意的 i = 0, ..., k - 1 有 ai AND ai + 1 = ai + 1。其中AND是與操作。

</pre><pre name="code" class="java">#include<iostream>
using namespace std;
#define MOD 1000000009 

int calc(int k,int n)
{
	int temp,i,j;;
	int result[10001]={0};
	int result_tem[10001]={0};
	result[0]=1;
	result_tem[0]=1;
	for(temp=1;temp<=n;temp*=2)  //表示每個二進制位
	{
		for(i=1;i<=k;i++)        //表示每個二進制位上選擇1的個數
		{
			for(j=0;j<=n-temp*i;j++)  
			{
				result_tem[j+temp*i]+=result[j]; //由於每個二進制位選擇1的個數只能爲一個整數(多重揹包和0/1揹包問題)
				result_tem[j+temp*i]%=MOD;
			}
		}
		for(j=0;j<=n;j++)
			result[j]=result_tem[j];
	}	
	return result[n];
}
int main()
{
	int i,n;
	int k,m;
	cin >> n;
	for(i=0;i<n;i++)
	{
		cin >> k >> m;
		int result =calc(k,m);
		cout << result << endl;
	}
	return 0;
} 

輸入:

2

3 2

4 2

輸出:

2

2

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章