BZOJ3717 PA2014Pakowanie(状压dp)
显然贪心地有尽量先往容量大的背包里放。设f[i]为i子集物品最小占用背包数,g[i]为该情况下最后一个背包的剩余容量,转移显然。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } #define N 24 #define M 102 int n,m,a[N],b[M],f[1<<N],g[1<<N],lg2[1<<N]; int main() { #ifndef ONLINE_JUDGE freopen("bzoj3717.in","r",stdin); freopen("bzoj3717.out","w",stdout); const char LL[]="%I64d\n"; #else const char LL[]="%lld\n"; #endif n=read(),m=read(); for (int i=0;i<n;i++) a[i]=read(); for (int i=1;i<=m;i++) b[i]=read(); sort(b+1,b+m+1);reverse(b+1,b+m+1); for (int i=0;i<n;i++) lg2[1<<i]=i; memset(f,42,sizeof(f)); f[0]=0;int s=(1<<n)-1; for (int i=0;i<(1<<n);i++) if (f[i]<=m) for (int j=s^i,t=j&-j;j;j^=t,t=j&-j) if (g[i]>=a[lg2[t]]) { if (f[i]<f[i|t]) f[i|t]=f[i],g[i|t]=g[i]-a[lg2[t]]; else if (f[i]==f[i|t]) g[i|t]=max(g[i|t],g[i]-a[lg2[t]]); } else if (b[f[i]+1]>=a[lg2[t]]) { if (f[i]+1<f[i|t]) f[i|t]=f[i]+1,g[i|t]=b[f[i|t]]-a[lg2[t]]; else if (f[i]+1==f[i|t]) g[i|t]=max(g[i|t],b[f[i|t]]-a[lg2[t]]); } if (f[(1<<n)-1]>m) cout<<"NIE"; else cout<<f[(1<<n)-1]; return 0; }