题目链接
题目描述
给定一个代表集装箱载重的数组 capacities 和一个代表货物重量的数组 weights。一个集装箱内可以装入多件货物,只要总重量不超过其载重。但由于货物不可分割,一件货物必须完整地装入一个集装箱。
你需要找出一种装箱方案,使得能够被成功装箱的货物数量最多。
输入:
- 集装箱数量
和各自的载重量。
- 货物数量
和各自的重量。
输出:
- 一个整数,表示最多可以成功装箱的货物数量。
解题思路
这个问题需要我们最大化装入集装箱的货物数量,且每个集装箱可以装载多件货物。这是一个典型的贪心问题。
核心思想:为了装下尽可能多的货物,我们应该优先使用最小的货物去填充最小的集装箱。
-
排序
- 对货物重量
weights和集装箱容量capacities都进行 升序 排序。 - 排序货物是为了确保我们总是优先考虑最轻的、最容易装箱的货物。
- 排序集装箱是为了确保我们总是优先使用容量最小的、最受限的资源,从而为更重的货物保留更大的集装箱。
- 对货物重量
-
贪心填充 (双指针法)
- 我们使用两个指针:
item_idx指向当前待装箱的最轻的货物,container_idx指向当前待填充的最小的集装箱。 - 外层循环遍历每一个集装箱(从小到大)。
- 对于当前的集装箱,内层循环尝试用当前可用的、最轻的货物去填充它,直到装满或者没有更小的货物能装下为止。
- 由于两个数组都已排序,
item_idx指针在整个过程中只需要向前移动,不需要回溯。
- 我们使用两个指针:
-
算法流程
- 初始化
item_idx = 0。最终装箱的货物数量就是item_idx的值。 - 遍历
capacities数组中的每个capacity:- 创建一个变量
current_capacity记录当前集装箱的剩余容量。 - 当
item_idx未越界且weights[item_idx] <= current_capacity时,循环:- 将当前货物装入:
current_capacity -= weights[item_idx]。 - 移动货物指针:
item_idx++,表示该货物已被装箱。
- 将当前货物装入:
- 创建一个变量
- 初始化
-
终止
- 遍历完所有集装箱后,
item_idx的值即为最终答案。
- 遍历完所有集装箱后,
代码
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(NULL);
int n_containers;
cin >> n_containers;
vector<long long> capacities(n_containers);
for (int i = 0; i < n_containers; ++i) {
cin >> capacities[i];
}
int n_items;
cin >> n_items;
vector<int> weights(n_items);
for (int i = 0; i < n_items; ++i) {
cin >> weights[i];
}
sort(capacities.begin(), capacities.end());
sort(weights.begin(), weights.end());
int item_ptr = 0;
for (int i = 0; i < n_containers; ++i) {
long long current_capacity = capacities[i];
while (item_ptr < n_items && weights[item_ptr] <= current_capacity) {
current_capacity -= weights[item_ptr];
item_ptr++;
}
}
cout << item_ptr << endl;
return 0;
}
import java.util.Scanner;
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int nContainers = sc.nextInt();
long[] capacities = new long[nContainers];
for (int i = 0; i < nContainers; i++) {
capacities[i] = sc.nextLong();
}
int nItems = sc.nextInt();
int[] weights = new int[nItems];
for (int i = 0; i < nItems; i++) {
weights[i] = sc.nextInt();
}
Arrays.sort(capacities);
Arrays.sort(weights);
int itemPtr = 0;
for (int i = 0; i < nContainers; i++) {
long currentCapacity = capacities[i];
while (itemPtr < nItems && weights[itemPtr] <= currentCapacity) {
currentCapacity -= weights[itemPtr];
itemPtr++;
}
}
System.out.println(itemPtr);
}
}
def main():
n_containers = int(input())
capacities = list(map(int, input().split()))
n_items = int(input())
weights = list(map(int, input().split()))
capacities.sort()
weights.sort()
item_ptr = 0
for capacity in capacities:
current_capacity = capacity
while item_ptr < n_items and weights[item_ptr] <= current_capacity:
current_capacity -= weights[item_ptr]
item_ptr += 1
print(item_ptr)
if __name__ == "__main__":
main()
算法及复杂度
- 算法:贪心、排序、双指针
- 时间复杂度:
,其中
是集装箱数量,
是货物数量。算法的瓶颈在于对两个数组的排序。排序后的双指针遍历过程是线性的,时间复杂度为
。
- 空间复杂度:
或
,取决于排序算法所使用的额外栈空间。不考虑输入数组本身占用的空间。

京公网安备 11010502036488号