[bzoj2621] [USACO12MAR]摩天大楼里的奶牛Cows in a Skyscraper
状压\(dp\)
根据套路,先设\(f[sta]\)为状态为\(sta\)时所用的最小分组数。
可以发现,这个状态不好转移,无法判断是否可以装下新的一个物品。于是再设一个状态\(g[sta]\)表示状态为\(sta\)时 每组剩下的体积的最大值 的最大值,当枚举状态为\(sta\),枚举到第\(i\)个时,可以得到\(g\)的转移:
\[g[v]=max(g[v],g[sta]-w[i])
\]
其中,\(v\)为转移后的状态。
然后每次就可以根据\(g\)来转移\(f\)了。
#pragma GCC optimize(3)
#include<bits/stdc++.h>
using namespace std;
void read(int &x){
x=0;int f=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
for(;isdigit(ch);ch=getchar()) x=(x<<1)+(x<<3)+ch-'0';x*=f;
}
#define write(x) printf("%d\n",x)
int f[(1<<18)+10],g[(1<<18)+10],n,w[20],W;
int main(){
read(n),read(W);for(int i=1;i<=n;i++) read(w[i]);
memset(f,63,sizeof f);f[0]=1,g[0]=W;
for(int i=0;i<(1<<n);i++)
for(int j=1,v=i|(1<<(j-1));j<=n;j++,v=i|(1<<(j-1)))
if(!(i&(1<<(j-1))))
if(g[i]>=w[j]&&f[i]<=f[v]) f[v]=f[i],g[v]=max(g[v],g[i]-w[j]);
else if(g[i]<w[j]&&f[i]+1<=f[v]) f[v]=f[i]+1,g[v]=max(g[v],W-w[j]);
write(f[(1<<n)-1]);
return 0;
}