[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


这题设f[sta]表示选取物品状态为sta时最少要用多少包,g[sta]表示最后那个包用了多少空间。由于包肯定是先用大的再用小的,所以我们可以很容易得到包的剩余容量,然后瞎jb转移一下就好了

/*program from Wolfycz*/
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define inf 0x7f7f7f7f
using namespace std;
typedef long long ll;
typedef unsigned int ui;
typedef unsigned long long ull;
inline int read(){
	int x=0,f=1;char ch=getchar();
	for (;ch<'0'||ch>'9';ch=getchar())	if (ch=='-')    f=-1;
	for (;ch>='0'&&ch<='9';ch=getchar())	x=(x<<1)+(x<<3)+ch-'0';
	return x*f;
}
inline void print(int x){
	if (x>=10)	print(x/10);
	putchar(x%10+'0');
}
const int N=24,M=1e2;
int f[(1<<N)+10],g[(1<<N)+10],A[N+10],C[M+10];
bool cmp(int x,int y){return x>y;}
int main(){
	int n=read(),m=read();
	for (int i=0;i<n;i++)	A[i]=read();
	for (int i=1;i<=m;i++)	C[i]=read();
	sort(C+1,C+1+m,cmp);
	memset(f,127,sizeof(f)),f[0]=0;
	for (int sta=0;sta<1<<n;sta++){
		for (int i=0;i<n;i++){
			if (sta&(1<<i)){
				int tmp=f[sta^(1<<i)]+(C[f[sta^(1<<i)]]<(g[sta^(1<<i)]+A[i]));
				int res=(tmp==f[sta^(1<<i)])?g[sta^(1<<i)]+A[i]:A[i];
				if (res>C[tmp])	continue;
				if (tmp<f[sta])	f[sta]=tmp,g[sta]=inf;
				if (tmp==f[sta])	g[sta]=min(g[sta],res);
			}
		}
	}
	printf(f[(1<<n)-1]==inf?"NIE
":"%d
",f[(1<<n)-1]);
	return 0;
}
原文地址:https://www.cnblogs.com/Wolfycz/p/9683187.html