作为一个oier,以及大学acm党背包是必不可少的一部分。好久没做背包类动规了。久违地练习下-。-
dd__engi的背包九讲:http://love-oriented.com/pack/
鸣谢http://blog.csdn.net/eagle_or_snail/article/details/50987044,这里有大部分比较有趣的dp练手题。
hdu 2844 Coins 多重背包
就是一个10w的多重背包,每个物品的cost同时也作为value去做背包,我们求的是每个容量下的价值,所以没法做背包九讲里提到的对最终目标的常数优化。那么我们做完以后,统计一下背包里dp[i]==i的空间i总数即为答案。
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #define clr(x) memset(x,0,sizeof(x)) 5 #define MAXN 100010 6 using namespace std; 7 int dp[MAXN]; 8 struct node 9 { 10 int num,cost; 11 }good[MAXN]; 12 int n,m,s,t,l,k,ans; 13 int max(int a,int b) 14 { 15 return a>b?a:b; 16 } 17 void zeroonepack(int cost,int val) 18 { 19 for(int i=m;i>=cost;i--) 20 { 21 dp[i]=max(dp[i],dp[i-cost]+val); 22 } 23 return ; 24 } 25 void completepack(int cost,int val) 26 { 27 for(int i=cost;i<=m;i++) 28 { 29 dp[i]=max(dp[i],dp[i-cost]+val); 30 } 31 return ; 32 } 33 void multipack(int cost,int val,int num) 34 { 35 if(cost*num>=m) 36 { 37 completepack(cost,val); 38 } 39 else 40 { 41 int t=1; 42 while(t<=num) 43 { 44 zeroonepack(t*cost,t*val); 45 num-=t; 46 t*=2; 47 } 48 zeroonepack(num*cost,num*val); 49 } 50 return ; 51 } 52 int main() 53 { 54 while(scanf("%d%d",&n,&m)!=EOF && m!=0 && n!=0) 55 { 56 clr(dp); 57 for(int i=1;i<=n;i++) 58 { 59 scanf("%d",&good[i].cost); 60 } 61 for(int i=1;i<=n;i++) 62 { 63 scanf("%d",&good[i].num); 64 } 65 for(int i=1;i<=n;i++) 66 { 67 multipack(good[i].cost,good[i].cost,good[i].num); 68 } 69 ans=0; 70 for(int i=1;i<=m;i++) 71 { 72 if(dp[i]==i) 73 ans++; 74 } 75 printf("%d\n",ans); 76 } 77 return 0; 78 }
多重背包
hdu 2159 FATE 完全背包
一个二维完全背包,将消耗忍耐度和杀怪数作为二维的cost,然后将求解每个忍耐度和杀怪数下经验值的最大值作为最大价值。我们做一遍二维完全背包,然后找杀怪数满(即dp[s][i])时最小的经验值超过升级所需经验值n的i,这个i即为最小忍耐度,然后m-i即为答案。
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #define clr(x) memset(x,0,sizeof(x)) 5 #define MAXN 110 6 using namespace std; 7 int dp[MAXN][MAXN],v[MAXN],c[MAXN]; 8 int n,m,k,s,t,l,ans,minn; 9 int max(int a,int b) 10 { 11 return a>b?a:b; 12 } 13 int main() 14 { 15 while(scanf("%d%d%d%d",&n,&m,&k,&s)!=EOF) 16 { 17 clr(dp); 18 for(int i=1;i<=k;i++) 19 { 20 scanf("%d%d",&v[i],&c[i]); 21 } 22 for(int i=1;i<=k;i++) 23 { 24 for(int j=1;j<=s;j++) 25 { 26 for(int t=c[i];t<=m;t++) 27 dp[j][t]=max(dp[j][t],max(dp[j-1][t],dp[j-1][t-c[i]]+v[i])); 28 } 29 } 30 if(dp[s][m]<n) 31 { 32 printf("-1\n"); 33 } 34 else 35 { 36 minn=m; 37 for(int i=0;i<=m;i++) 38 if(dp[s][i]>=n && i<minn) 39 { 40 minn=i; 41 break; 42 } 43 printf("%d\n",m-minn); 44 } 45 } 46 return 0; 47 }
二维完全背包
poj 1170 Shopping Offers 状压+完全背包
最多五个物品,每个物品最多五件。因此可以将每个状态,cost,最终状态压缩成五位的六进制数,然后做求最小值的完全背包就行了。当然这题还是用编号的形式给出物品的,你需要把物品弄成连续的编号再做压缩操作。
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #define clr(x) memset(x,0,sizeof(x)) 5 #define clrmax(x) memset(x,0x3f3f3f3f,sizeof(x)) 6 #define MAXN 1000010 7 using namespace std; 8 int dp[MAXN]; 9 int v[MAXN],c[MAXN]; 10 int inf[MAXN]; 11 int bit(int n) 12 { 13 int l=1; 14 n--; 15 while(n--) 16 l*=6; 17 return l; 18 } 19 bool infer(int i,int j) 20 { 21 while(j) 22 { 23 if(i%6<j%6) 24 return false; 25 i/=6; 26 j/=6; 27 } 28 return true; 29 } 30 int main() 31 { 32 int n,m,maxn,ans,t,k,l,r,cnt,flag,num; 33 while(scanf("%d",&n)!=EOF) 34 { 35 m=0; 36 clr(inf); 37 clrmax(dp); 38 for(int i=1;i<=n;i++) 39 { 40 scanf("%d",&k); 41 inf[k]=i; 42 c[i]=bit(i); 43 scanf("%d%d",&num,&v[i]); 44 m+=bit(i)*num; 45 } 46 cnt=n; 47 scanf("%d",&k); 48 for(int i=1;i<=k;i++) 49 { 50 scanf("%d",&l); 51 flag=0; 52 r=0; 53 for(int i=1;i<=l;i++) 54 { 55 scanf("%d%d",&n,&t); 56 if(inf[n]==0 || flag==1) 57 { 58 flag=1; 59 continue; 60 } 61 r+=bit(inf[n])*t; 62 } 63 if(flag==0) 64 { 65 c[++cnt]=r; 66 scanf("%d",&v[cnt]); 67 } 68 else 69 { 70 scanf("%d",&r); 71 } 72 } 73 dp[0]=0; 74 for(int i=1;i<=cnt;i++) 75 { 76 for(int j=c[i];j<=m;j++) 77 if(infer(j,c[i])) 78 { 79 dp[j]=min(dp[j],dp[j-c[i]]+v[i]); 80 } 81 } 82 printf("%d\n",dp[m]); 83 } 84 return 0; 85 }
状压完全背包
时间: 2024-10-16 18:42:40