1. 程式人生 > >hdu 2844 混合背包【背包dp】

hdu 2844 混合背包【背包dp】

scan tar multiple -m -- 圖片 題解 void ring

http://acm.hdu.edu.cn/showproblem.php?pid=2844

題意:有n種紙幣面額(a1,a2,...an),每種面額對應有(c1,c2,...cn)張。問這些錢能拼成1-m中多少種值。

題解:背包dp問題。若ci=1,是01背包,若ci*ai>=m則是完全背包,否則是多重背包。(詳見《背包九講》)

先復習一下三種簡單背包形式:

 01背包(F[v] ← max{F[v], F[v ?Ci] +Wi} ):

 技術分享圖片

  

 完全背包(F[i, v] = max(F[i ? 1, v], F[i, v ?Ci] +Wi)):

  技術分享圖片

 多重背包(利用二進制思想轉化為01背包):

  技術分享圖片

利用三種背包形式就可以輕松解決此題:

  

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<queue>
 5 #include<vector>
 6 using namespace std;
 7 
 8 int f[100005];
 9 int c[105],a[105];
10 int n,m;
11 
12 void ZeroOnePack(int w,int v)
13 {
14     for(int j=m;j>=v;j--)
15 f[j]=max(f[j],f[j-w]+v); 16 } 17 18 void CompletePack(int w,int v) 19 { 20 for(int j=v;j<=m;j++) 21 f[j]=max(f[j],f[j-w]+v); 22 } 23 24 void MultiplePack(int w,int v,int c) 25 { 26 int k=1; 27 while(k<c) 28 { 29 ZeroOnePack(k*w,k*v); 30 c=c-k;k*=2
; 31 } 32 ZeroOnePack(c*w,c*v); 33 } 34 35 int main() 36 { 37 while(scanf("%d%d",&n,&m)==2) 38 { 39 memset(f,0,sizeof(f)); 40 if(n==0) break; 41 for(int i=1;i<=n;i++) scanf("%d",&a[i]); 42 for(int i=1;i<=n;i++) scanf("%d",&c[i]); 43 for(int i=1;i<=n;i++){ 44 if(c[i]==1) 45 ZeroOnePack(a[i],a[i]); 46 else if(c[i]*a[i]>=m) 47 CompletePack(a[i],a[i]); 48 else 49 MultiplePack(a[i],a[i],c[i]); 50 } 51 int ans=0; 52 for(int i=1;i<=m;i++) 53 if(f[i]==i) ans++; 54 printf("%d\n",ans); 55 } 56 return 0; 57 }

hdu 2844 混合背包【背包dp】