[PA2014]Pakowanie
[PA2014]Pakowanie
题目大意:
\(n(n\le24)\)个物品和\(m(m\le100)\)个背包,每个物体有一个体积\(a_i\),每个背包有一个容量\(c_i\)。问装完所有物品至少需要几个包?
思路:
一个贪心的策略是优先装大的包,显然这样可以最少化所用背包的数量。
将所有的背包按照容量从大到小排序,\(f[s]\)表示装了物品的状态为\(s\),用了前\(f[s]\)大的背包。\(g[s]\)表示装了物品的状态为\(s\),最后那个背包用了\(g[s]\)的容量。
随便转移就好了。
时间复杂度\(\mathcal O(2^nn)\)。
源代码:
#include<cstdio>
#include<cctype>
#include<climits>
#include<algorithm>
#include<functional>
inline int getint() {
register char ch;
while(!isdigit(ch=getchar()));
register int x=ch^'0';
while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
return x;
}
const int N=24,M=101;
int a[N],c[M],f[1<<N],g[1<<N];
int main() {
const int n=getint(),m=getint();
for(register int i=0;i<n;i++) a[i]=getint();
for(register int i=1;i<=m;i++) c[i]=getint();
std::sort(&c[1],&c[m]+1,std::greater<int>());
std::fill(&f[1],&f[1<<n],INT_MAX);
for(register int i=1;i<1<<n;i++) {
for(register int j=0;j<n;j++) {
if(!((i>>j)&1)) continue;
const int k=i^(1<<j);
const int tmp1=g[k]+a[j]<=c[f[k]]?f[k]:f[k]+1;
const int tmp2=tmp1==f[k]?g[k]+a[j]:a[j];
if(tmp2>c[tmp1]) continue;
if(tmp1<f[i]) {
f[i]=tmp1;
g[i]=INT_MAX;
}
if(tmp1==f[i]) g[i]=std::min(g[i],tmp2);
}
}
if(f[(1<<n)-1]==INT_MAX) {
puts("NIE");
return 0;
}
printf("%d\n",f[(1<<n)-1]);
return 0;
}