bzoj3717 [PA2014]Pakowanie

Description

你有n个物品和m个包。物品有重量,且不可被分割;包也有各自的容量。要把所有物品装入包中,至少需要几个包?

Input

第一行两个整数n,m(1<=n<=24,1<=m<=100),表示物品和包的数量。
第二行有n个整数a[1],a[2],…,a[n](1<=a[i]<=10^8),分别表示物品的重量。
第三行有m个整数c[1],c[2],…,c[m](1<=c[i]<=10^8),分别表示包的容量。

Output

如果能够装下,输出一个整数表示最少使用包的数目。若不能全部装下,则输出NIE。

Sample Input

4 3
4 2 10 3
11 18 9

Sample Output

2

 

正解:背包+状压$dp$。

这道题只有$24$个物品,我们可以考虑状压。

还有一个很显然的事,背包肯定是从大到小填的。

那么我们就可以直接开始$dp$了,设$f[S]$表示当前物品集合为$S$,且当前背包所用容量为$f[S]$,$g[S]$为当前背包的编号,也就是背包数量。

那么每次我们可以枚举一个物品加进来,如果没有炸掉当前背包,就可以直接填进去,否则就要开一个新背包,如果连新背包都开不下,那么这个转移就是不合法的。

 

 1 #include <bits/stdc++.h>
 2 #define il inline
 3 #define RG register
 4 #define ll long long
 5 #define lb(x) (x & -x)
 6 #define inf (2147483640)
 7 #define SIZE (16777216)
 8 
 9 using namespace std;
10 
11 int f[SIZE],g[SIZE],bin[SIZE],a[110],c[110],n,m;
12 
13 il int gi(){
14   RG int x=0,q=1; RG char ch=getchar();
15   while ((ch<'0' || ch>'9') && ch!='-') ch=getchar();
16   if (ch=='-') q=-1,ch=getchar();
17   while (ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar();
18   return q*x;
19 }
20 
21 int main(){
22 #ifndef ONLINE_JUDGE
23   freopen("Pakowanie.in","r",stdin);
24   freopen("Pakowanie.out","w",stdout);
25 #endif
26   n=gi(),m=gi();
27   for (RG int i=0;i<n;++i) a[i]=gi(),bin[1<<i]=i;
28   for (RG int i=1;i<=m;++i) c[i]=gi();
29   sort(c+1,c+m+1),reverse(c+1,c+m+1),m=min(m,n+1);
30   for (RG int S=1,all=1<<n;S<all;++S){
31     f[S]=inf,g[S]=m+1;
32     for (RG int i=S,s,x,res,tim;i;i^=s){
33       s=lb(i),res=f[S^s],tim=g[S^s];
34       if (res==inf) continue; x=bin[s];
35       if (res+a[x]<=c[tim]) res+=a[x];
36       else if (tim==m || c[tim+1]<a[x]) continue;
37       else res=a[x],++tim;
38       if (g[S]>tim) f[S]=res,g[S]=tim;
39       else if (g[S]==tim && f[S]>res) f[S]=res;
40     }
41   }
42   if (f[(1<<n)-1]==inf) puts("NIE");
43   else cout<<g[(1<<n)-1]; return 0;
44 }

 

posted @ 2017-10-14 18:23  wfj_2048  阅读(217)  评论(0编辑  收藏  举报