背包系列练习( hdu 2844 Coins && hdu 2159 && poj 1170 Shopping Offers && hdu 3092

Posted hk lin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了背包系列练习( hdu 2844 Coins && hdu 2159 && poj 1170 Shopping Offers && hdu 3092 相关的知识,希望对你有一定的参考价值。

作为一个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 }
状压完全背包

 

以上是关于背包系列练习( hdu 2844 Coins && hdu 2159 && poj 1170 Shopping Offers && hdu 3092 的主要内容,如果未能解决你的问题,请参考以下文章

HDU 2844 Coins (多重背包问题DP)

HDU - 2844 Coins(多重背包+完全背包)

背包专题 D - Coins hdu2844多重背包

hdu2844 Coins

hdu2844Coins(多重背包模板)

hdu2844 Coins 多重背包