【hdu3033】分组背包(每组最少选一个)

【题意】

有S款运动鞋,一个n件,总钱数为m,求不超过总钱数且每款鞋子至少买一双的情况下,使价值最大。如果有一款买不到,就输出“Impossible"。

1<=N<=100  1 <= M<= 10000 

【题解】

首先明显这是一个分组背包。

impossible 就直接看看每组最便宜的是否买得起。

因为每组最少选一个,所以我们可以这样dp:

f[k][j]表示当前扫到第k组,容量为j。

f[k][j]可由三个更新:

f[k][j]=f[k][j] 不选当前物品

f[k][j]=f[k-1][j-b[i]]+c[i] 选择当前物品,并且是在该组中第一次选物品

f[k][j]=f[k][j-b[i]]+c[i] 选择当前物品,并且不是在该组中第一次选

因为f[k][j]初始值为0,所以它最少都会买一样东西(由第二条更新得到)

 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cstring>
 4 #include<iostream>
 5 #include<algorithm>
 6 #include<queue>
 7 #include<vector>
 8 using namespace std;
 9 
10 const int N=11000,S=110;
11 int n,m,K,a[N],b[N],c[N],mn[S],d[S][S],f[S][N];
12 
13 int maxx(int x,int y){return x>y ? x:y;}
14 int minn(int x,int y){return x<y ? x:y;}
15 
16 int main()
17 {
18     freopen("a.in","r",stdin);
19     while(scanf("%d%d%d",&n,&m,&K)!=EOF)
20     {
21         memset(d,0,sizeof(d));
22         memset(mn,63,sizeof(mn));
23         for(int i=1;i<=n;i++) 
24         {
25             scanf("%d%d%d",&a[i],&b[i],&c[i]);
26             d[a[i]][++d[a[i]][0]]=i;
27             mn[a[i]]=minn(mn[a[i]],b[i]);
28         }
29         int x=0;
30         for(int i=1;i<=K;i++) x+=mn[i];
31         if(m<x) printf("Impossible
");
32         else
33         {
34             memset(f,0,sizeof(f));
35             for(int k=1;k<=K;k++)
36             {
37                 for(int i=1;i<=d[k][0];i++)
38                 {
39                     x=d[k][i];
40                     for(int j=m;j>=b[x];j--)
41                     {
42                         f[k][j]=maxx(f[k][j],maxx(f[k-1][j-b[x]]+c[x],f[k][j-b[x]]+c[x]));
43                     }
44                 }
45             }
46             printf("%d
",f[K][m]);
47         }
48     }
49     return 0;
50 }
原文地址:https://www.cnblogs.com/KonjakJuruo/p/5971968.html