REALHW84 星港交通调度
题目链接
题目描述
在“天穹站”太空港,你需要为 艘申请停泊的星舰分配泊位。空间站共分
个层级,每层有
个泊位。
停泊规则:
- 每艘星舰
有一个首选停泊层级
和船员人数
。
- 星舰只能被安排在其首选层级或其下方的任意层级(直至最底部的1层)。
能源消耗:
- 总能耗公式: 对于一艘首选层级为
,最终停在
层 (
),载有
名船员的星舰,其单次任务能耗为:
。
任务目标:
为所有 艘星舰找到一个停泊方案,使得总能耗(所有星舰的能耗之和)达到最小值。如果泊位不足以容纳所有星舰,则输出 -1。
解题思路
这是一道贪心算法优化问题。我们的目标是最小化所有星舰的总能耗。
首先,分析总能耗公式:
展开这个和式:
在这个表达式中,第一部分 是一个常数。因此,要使
最小,我们必须最大化第二部分
。
问题转化为:如何为星舰分配停泊层级 ,以最大化所有星舰的“船员数
停泊层级”之和。为了实现这一目标,我们应该遵循一个贪心原则:将船员数量更多 (
值大) 的星舰,安排在尽可能高 (
值大) 的可用层级。
基于此,我们设计出如下的贪心算法:
- 数据预处理: 将所有星舰按照其首选层级
分组。同时,计算出能耗公式中的常量部分
。
- 贪心分配:
- 我们从最高层级
开始,向下遍历至层级 1。
- 维护一个“候选池”(大顶堆),存放所有当前可以停泊但尚未分配泊位的星舰。
- 当遍历到层级
时,将所有首选层级为
的星舰全部加入大顶堆中。
- 从大顶堆中连续取出船员数最多的星舰,最多取
次,并将它们安排在当前层级
。
- 我们从最高层级
- 最终检查: 在贪心分配结束后,必须检查是否所有
艘星舰都被成功分配。即使总泊位
F*M大于等于N,也可能因为局部泊位不足(例如所有星舰都申请停在高层)导致无法安排。如果成功分配的星舰总数小于,则说明方案不可行,应输出 -1。
- 计算最终结果: 如果所有星舰都成功分配,则计算最终能耗。
代码
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(NULL);
long long f, m, n;
cin >> f >> m >> n;
if (n > f * m) {
cout << -1 << endl;
return 0;
}
vector<vector<int>> ships_by_pref(f + 1);
long long total_cost = 0;
for (int i = 0; i < n; ++i) {
int r, p;
cin >> r >> p;
ships_by_pref[r].push_back(p);
// 先累加能耗公式中的固定部分 P * (2 + R)
total_cost += (long long)p * (2 + r);
}
priority_queue<int> available_ships;
long long assigned_ships_count = 0;
for (int current_level = f; current_level >= 1; --current_level) {
for (int crew : ships_by_pref[current_level]) {
available_ships.push(crew);
}
for (int i = 0; i < m && !available_ships.empty(); ++i) {
int top_crew = available_ships.top();
available_ships.pop();
// 减去通过贪心最大化的 P * A 部分
total_cost -= (long long)top_crew * current_level;
assigned_ships_count++;
}
}
if (assigned_ships_count < n) {
cout << -1 << endl;
} else {
cout << total_cost << endl;
}
return 0;
}
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
long f = sc.nextLong();
long m = sc.nextLong();
long n = sc.nextLong();
if (n > f * m) {
System.out.println(-1);
return;
}
List<List<Integer>> shipsByPref = new ArrayList<>();
for (int i = 0; i <= f; i++) {
shipsByPref.add(new ArrayList<>());
}
long totalCost = 0;
for (int i = 0; i < n; i++) {
int r = sc.nextInt();
int p = sc.nextInt();
shipsByPref.get(r).add(p);
// 先累加能耗公式中的固定部分 P * (2 + R)
totalCost += (long)p * (2 + r);
}
PriorityQueue<Integer> availableShips = new PriorityQueue<>(Collections.reverseOrder());
long assignedShipsCount = 0;
for (int currentLevel = (int)f; currentLevel >= 1; currentLevel--) {
for (int crew : shipsByPref.get(currentLevel)) {
availableShips.add(crew);
}
for (int i = 0; i < m && !availableShips.isEmpty(); i++) {
int topCrew = availableShips.poll();
// 减去通过贪心最大化的 P * A 部分
totalCost -= (long)topCrew * currentLevel;
assignedShipsCount++;
}
}
if (assignedShipsCount < n) {
System.out.println(-1);
} else {
System.out.println(totalCost);
}
}
}
import heapq
def solve():
f, m, n = map(int, input().split())
if n > f * m:
print(-1)
return
ships_by_pref = [[] for _ in range(f + 1)]
total_cost = 0
for _ in range(n):
r, p = map(int, input().split())
ships_by_pref[r].append(p)
# 先累加能耗公式中的固定部分 P * (2 + R)
total_cost += p * (2 + r)
available_ships_heap = []
assigned_ships_count = 0
for current_level in range(f, 0, -1):
for crew in ships_by_pref[current_level]:
heapq.heappush(available_ships_heap, -crew)
for _ in range(m):
if not available_ships_heap:
break
top_crew_neg = heapq.heappop(available_ships_heap)
crew = -top_crew_neg
# 减去通过贪心最大化的 P * A 部分
total_cost -= crew * current_level
assigned_ships_count += 1
if assigned_ships_count < n:
print(-1)
else:
print(total_cost)
solve()
算法及复杂度
- 算法: 贪心算法, 优先队列 (堆)
- 时间复杂度:
- 空间复杂度:

京公网安备 11010502036488号