[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;
}
posted @ 2018-08-13 20:20  skylee03  阅读(353)  评论(0编辑  收藏  举报