[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
",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;
}

原文地址:https://www.cnblogs.com/hbyer/p/9832655.html