洛谷 P3052 [USACO12MAR]Cows in a Skyscraper G 状压DP

nn 头牛上电梯,电梯固定最大载重 WW,每头牛重 w[i]w[i] ,问至少需要使用几次电梯才能把牛都运上楼?

思路:n18n\le 18 ,因此显然状压DP,用 f[i]f[i] 来表示状态为 ii 时的最少使用次数,g[i]g[i] 表示状态为 ii 时,当前使用电梯的剩余空间。ii 的每一个二进制位表示一头牛是否已经上过电梯。

// 状压DP
#include<iostream>
#include<cstdio>
#include<cstring>
#define MAXN 20
#define INF 0x3f3f3f3f
using namespace std;
int n,W; // 个数以及最大重量
int w[MAXN]; // 每头牛的重量
int f[1<<18],g[1<<18]; // f[i] 表示状态为 i 时的最小次数,g[i] 表示状态为 i 时最后一个电梯的剩余体积
int main(){
#ifdef WINE
    freopen("data.in","r",stdin);
#endif
    scanf("%d%d",&n,&W);
    for(int i=1;i<=n;i++)scanf("%d",&w[i]);
    memset(f,INF,sizeof(f));
    f[0]=1;g[0]=W;
    for(int i=0;i<(1<<n);i++){ // 对于每一个状态
        for(int j=1;j<=n;j++){ // 枚举每一个奶牛
            if(i&(1<<(j-1)))continue; // 已经在电梯内
            if(g[i]>=w[j]&&f[i|(1<<(j-1))]>=f[i]){ // 可以坐得下
                f[i|(1<<(j-1))]=f[i]; // 更新状态对应的计数
                g[i|(1<<(j-1))]=max(g[i|(1<<(j-1))],g[i]-w[j]); // 更新剩余体积
            }else if(g[i]<w[j]&&f[i|(1<<(j-1))]>=f[i]+1){ // 坐不下,并且次数增加之后仍有可能成为最优解
                f[i|(1<<(j-1))]=f[i]+1; // 更新使用电梯的次数
                g[i|(1<<(j-1))]=max(g[i|(1<<(j-1))],W-w[j]); // 更新剩余的体积
            }
        }
    }
    printf("%d\n",f[(1<<n)-1]);
    return 0;
}

posted @ 2020-07-10 16:45  winechord  阅读(89)  评论(0编辑  收藏  举报