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
4 2 10 3
11 18 9
Sample Output
2
首先我们有贪心的思想就是背包肯定是从大往小选。
再接着由于物品数$n<=24$,我们可以拿来状压。
设$f[S]$表示当前物品集合为$S$,且当前背包所用容量为$f[S]$,$g[S]$为当前背包的编号,也就是背包数量。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 int f[(1<<24)-1],id[(1<<24)-1],g[(1<<24)-1]; 7 int a[25],c[101],n,m,inf=2e9; 8 bool cmp(int a,int b) 9 { 10 return a>b; 11 } 12 int lowbit(int x) 13 { 14 return x&(-x); 15 } 16 int main() 17 {int i,j; 18 cin>>n>>m; 19 for (i=1;i<=n;i++) 20 { 21 scanf("%d",&a[i]); 22 id[(1<<i-1)]=i; 23 } 24 for (i=1;i<=m;i++) 25 { 26 scanf("%d",&c[i]); 27 } 28 sort(c+1,c+m+1,cmp); 29 for (i=1;i<(1<<n);i++) 30 { 31 g[i]=m+1; 32 f[i]=inf; 33 for (j=i;j;j-=lowbit(j)) 34 { 35 int S=i-lowbit(j); 36 int tim=g[S],res=f[S]; 37 if (res==inf) continue; 38 if (res+a[id[lowbit(j)]]<=c[tim]) res+=a[id[lowbit(j)]]; 39 else if (tim==m||c[tim+1]<a[id[lowbit(j)]]) continue; 40 else {res=a[id[lowbit(j)]];tim++;} 41 if (tim<g[i]) f[i]=res,g[i]=tim; 42 else if (g[i]==tim&&f[i]>res) f[i]=res; 43 } 44 } 45 if (f[(1<<n)-1]==inf) cout<<"NIE"; 46 else 47 cout<<g[(1<<n)-1]; 48 }
那么每次我们可以枚举一个物品加进来,如果没有炸掉当前背包,就可以直接填进去,否则就要开一个新背包,如果连新背包都开不下,那么这个转移就是不合法的