洛谷 P3052:[USACO12MAR] Cows in a Skyscraper G ← 状态压缩DP

​【题目来源】
https://www.luogu.com.cn/problem/P3052

【题目描述】
一个鲜为人知的事实是,Bessie 和她的朋友们喜欢爬楼梯比赛。一个更为人知的事实是,奶牛们真的不喜欢下楼梯。因此,当奶牛们比赛到达她们最喜欢的摩天大楼的顶层后,她们遇到了一个问题。拒绝使用楼梯下楼,奶牛们被迫使用电梯返回地面层。
电梯的最大载重量为 W 磅 (1≤W≤10^8),奶牛 i 的体重为 Ci 磅 (1≤Ci≤W)。请帮助 Bessie 找出如何用最少的电梯次数将所有 N 头奶牛 (1≤N≤18) 送到地面层。每次电梯的总重量不能超过 W。

【输入格式】
第 1 行:用空格分隔的 N 和 W。
第 2 行到第 1+N 行:第 i+1 行包含一个整数 Ci,表示一头奶牛的体重。​​​​​​​

【输出格式】
一个整数 R,表示所需的最少电梯次数。

【输入样例】
4 10 
5 
6 
3 
7 

【输出样例】
3

【数据范围】
1≤W≤10^8,1≤Ci≤W,1≤N≤18

【说明/提示】
有四头奶牛,体重分别为 5、6、3 和 7 磅。电梯的最大载重量为 10 磅。
我们可以将体重为 3 的奶牛与其他任何一头奶牛放在同一个电梯上,但其他三头奶牛太重,无法组合在一起。对于上述解决方案,电梯行程 1 包括奶牛 1 和 3,电梯行程 2 包括奶牛 2,电梯行程 3 包括奶牛 4。对于此输入,还有其他几种可能的解决方案。​​​​​​​

【算法分析】
dp[mask]:把 mask 里的牛全部运走,所需要的最小趟数。
rest[mask]:在所有满足「趟数 = dp[mask]」的方案中,最后一趟电梯剩下的最大空余载重。

【算法代码】

#include <bits/stdc++.h>
using namespace std;

typedef long long LL;
const int inf=0x3f3f3f3f;
const int N=20;
LL rest[1<<N],c[N];
int dp[1<<N];

int main() {
    memset(dp,inf,sizeof dp);
    int n,w;
    cin>>n>>w;
    dp[0]=0,rest[0]=0;
    for(int i=0; i<n; i++) cin>>c[i];

    for(int mask=0; mask<(1<<n); mask++) {
        if(dp[mask]==inf) continue;
        for(int i=0; i<n; i++) {
            if(mask&(1<<i)) continue;
            int nxt=mask|(1<<i);
            LL new_dp,new_rest;
            if(c[i]<=rest[mask]) {
                new_dp=dp[mask];
                new_rest=rest[mask]-c[i];
            } else {
                new_dp=dp[mask]+1;
                new_rest=w-c[i];
            }

            if(new_dp<dp[nxt]) {
                dp[nxt]=new_dp;
                rest[nxt]=new_rest;
            } else if(new_dp==dp[nxt]) {
                rest[nxt]=max(rest[nxt],new_rest);
            }
        }
    }
    cout<<dp[(1<<n)-1]<<endl;

    return 0;
}

/*
in:
4 10
5
6
3
7

out:
3
*/



【参考文献】
https://www.luogu.com.cn/problem/solution/P3052

 

​

posted @ 2026-11-09 14:00  Triwa  阅读(3)  评论(0)    收藏  举报