1. 程式人生 > >HDU 2844 多重背包

HDU 2844 多重背包

can class 01背包 rop c++ bsp use #define 完全背包

題目鏈接:http://acm.hdu.edu.cn/showproblem.php?pid=2844

解題思路:

  這題實際上就是能否用所給硬幣組合出某個價格,然後統計能組合出的價格的總數,然後每個硬幣個數不一,所以很明顯是多重背包。

  對於多重背包我們用二進制優化,也就是對 num 個 a 物品按二進制進行分組,分出的每一組看做一種物品,那麽就轉化為01背包了。所以這題也算是標準的模板題了,有個坑註意,題目中的M 可以為負數,小心。

代碼:

#include <bits/stdc++.h>
#define MAXS 100016
#define INF 0x3f3f3f3f
using
namespace std; /* hdu 2844*/ int n,m; //how many prices(form 1 to m) Tony can pay use these coins. //也就是算的是該價格能否被組合出來,統計能組合出來的價格的總數 //有個坑點 m 可能為負值 int value[102]; int num[102]; int f[MAXS]; // 完全背包 void competepack(int w,int v)//物重 價值 { for (int i=w;i<=m;++i) f[i] = max(f[i],f[i-w]+v); }
//01 背包 void onezeropack(int w,int v) // 01 背包 { for (int i = m;i>=w;i--) f[i] = max (f[i],f[i-w]+v); } void init()//這裏必須是恰好裝滿背包才行。所以這樣初始化而不是全初始化為0 { f[0] = 0; for (int i=1;i<=m;++i) f[i] = -INF; } int main () { while( (2 == scanf ("%d%d",&n,&m) ) && n!= 0
&& m!= 0 ) { init();//初始化 int ans = 0; //輸入價值和個數 for (int i=0;i<n;++i) scanf("%d",&value[i]); for (int i=0;i<n;++i) scanf("%d",&num[i]); if (m > 0 ) for (int i=0;i<n;++i) { if (value[i]*num[i] >= m) //這是就相當於是個完全背包。超過了總容量,不就相當個數無限嘛 competepack(value[i],value[i]); else // 多重背包進行分組轉化為01 背包 { //根據num[i]數目進行分組。 for (int k = 1; k < num[i]; k <<= 1 ) { onezeropack(value[i]*k,value[i]*k); num[i] -= k;//分組是按二進制,1,2,4,8... } if (num[i]) //如果最後分組還有剩 onezeropack(value[i]*num[i],value[i]*num[i]);//這一步是為了對最後剩下的num處理和當num==1時的處理 } } else { printf("%d\n", ans); continue; } for(int j = 1 ; j <= m ; ++j) if (f[j] > 0)//說明該容量的背包能被恰好裝滿,也就是該價格能由coins組合出來 ans++; //輸出答案 if (ans) printf("%d\n", ans); } return 0; }

HDU 2844 多重背包