1. 电梯调度问题解析
这个问题描述了一个经典的资源分配场景:有n个人需要乘坐电梯上楼,电梯有最大载重限制x,我们需要计算出最少需要多少趟才能把所有人都运送到楼上。这类问题在实际生活中非常常见,比如货物装箱、任务调度等场景。
1.1 问题重述与理解
给定:
- n个人,每个人的重量为w_i
- 电梯最大载重为x
- 每次电梯运行算作一趟
- 目标:找到运送所有人的最少趟数
约束条件:
- 1 ≤ n ≤ 20
- 1 ≤ x ≤ 10^9
- 1 ≤ w_i ≤ x
样例输入:
4 10
4 8 6 1
样例输出:
2
解释:可以第一趟运送8和1(总重9),第二趟运送4和6(总重10),共2趟。
1.2 问题复杂度分析
这是一个典型的组合优化问题,属于NP难问题。对于n=20的情况,暴力枚举所有可能的组合方式显然不可行,因为可能的组合数量是2^20=1,048,576种。我们需要一种更高效的算法来解决这个问题。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 动态规划解法思路
2.1 状态压缩DP简介
状态压缩动态规划(State Compression DP)是一种处理小规模组合问题的有效方法。它通过将集合的状态用二进制位表示,从而可以用整数来表示不同的子集状态。
在这个问题中:
- 每个人可以用一个二进制位表示(选或不选)
- 一个n位的二进制数可以表示所有人的选择状态
- 例如n=4时,二进制数1010表示选择第1和第3个人
2.2 DP状态设计
我们定义两个DP数组:
- dp[mask]:运送mask状态表示的人所需的最少趟数
- remain[mask]:在最少趟数的情况下,最后一趟的剩余载重
初始状态:
- dp[0] = 0(运送0个人需要0趟)
- remain[0] = 0(运送0个人时剩余载重为0)
2.3 状态转移方程
对于每个状态mask,我们尝试添加一个未被运送的人i(即mask的第i位为0):
- 如果当前最后一趟还能装下w[i]:
- 趟数不变:new_dp = dp[mask]
- 剩余载重减少:new_remain = remain[mask] - w[i]
- 如果当前最后一趟装不下w[i]:
- 需要新增一趟:new_dp = dp[mask] + 1
- 新一趟的剩余载重:new_remain = x - w[i]
然后我们比较new_dp和dp[new_mask]:
- 如果new_dp更小,直接更新
- 如果new_dp相同,选择remain更大的方案(为后续添加人员留更多空间)
3. 算法实现详解
3.1 初始化与输入处理
cpp复制#include<bits/stdc++.h>
using namespace std;
using ll=long long;
int w[20];
int dp[1<<20]; // 最少趟数
int remain[1
