星港交通调度
题目描述
空间站有 个停泊层级,每层有
个标准化泊位。
艘星舰申请停泊,每艘星舰
有首选层级
和船员数
。星舰只能停在首选层级或其下方任意层级。
停泊能耗公式:对于首选层级 、最终停在第
层、载有
名船员的星舰,能耗为
。
求所有星舰总能耗的最小值,若泊位不足输出 。
思路分析
关键转化
将总能耗展开:
$$
第一项 是常量(与分配方案无关)。因此,最小化总能耗等价于最大化
。
贪心策略
要最大化 ,直觉上应让船员数大的星舰尽量停在高层级。
从最高层级 向下遍历到第
层:
- 将首选层级等于当前层级的星舰加入候选池。
- 若候选池中星舰数
,全部停在当前层级。
- 若候选池中星舰数
,按船员数降序排序,前
艘停在当前层级,其余溢出到下一层级继续参与分配。
为什么这样是最优的? 高层级对 的贡献更大,而船员数
是该贡献的系数。在每一层,将船员数最大的
艘留下,能使它们乘以尽可能大的层级编号,从而最大化总贡献。溢出的低船员数星舰即使下移,损失也最小。
不可行判断
处理完第 层后,若候选池中仍有星舰未被分配(无法再下移),则输出
。
代码
[sol-C++]
#include <bits/stdc++.h>
using namespace std;
int main(){
int n, m, k;
scanf("%d%d%d", &n, &m, &k);
vector<vector<int>> ships(n + 1);
long long constantPart = 0;
for(int i = 0; i < k; i++){
int p, c;
scanf("%d%d", &p, &c);
ships[p].push_back(c);
constantPart += (long long)c * (2 + p);
}
long long sumCQ = 0;
vector<int> overflow;
for(int level = n; level >= 1; level--){
for(int c : ships[level]){
overflow.push_back(c);
}
if((int)overflow.size() <= m){
for(int c : overflow){
sumCQ += (long long)c * level;
}
overflow.clear();
continue;
}
sort(overflow.begin(), overflow.end(), greater<int>());
for(int i = 0; i < m; i++){
sumCQ += (long long)overflow[i] * level;
}
overflow = vector<int>(overflow.begin() + m, overflow.end());
}
if(!overflow.empty()){
printf("-1\n");
} else {
printf("%lld\n", constantPart - sumCQ);
}
return 0;
}
[sol-Java]
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt(), m = sc.nextInt(), k = sc.nextInt();
List<List<Integer>> ships = new ArrayList<>();
for (int i = 0; i <= n; i++) ships.add(new ArrayList<>());
long constantPart = 0;
for (int i = 0; i < k; i++) {
int p = sc.nextInt(), c = sc.nextInt();
ships.get(p).add(c);
constantPart += (long) c * (2 + p);
}
long sumCQ = 0;
List<Integer> overflow = new ArrayList<>();
for (int level = n; level >= 1; level--) {
overflow.addAll(ships.get(level));
if (overflow.size() <= m) {
for (int c : overflow) {
sumCQ += (long) c * level;
}
overflow.clear();
continue;
}
overflow.sort(Collections.reverseOrder());
for (int i = 0; i < m; i++) {
sumCQ += (long) overflow.get(i) * level;
}
overflow = new ArrayList<>(overflow.subList(m, overflow.size()));
}
if (!overflow.isEmpty()) {
System.out.println(-1);
} else {
System.out.println(constantPart - sumCQ);
}
}
}
[sol-Python3]
import sys
input = sys.stdin.readline
def main():
n, m, k = map(int, input().split())
ships = [[] for _ in range(n + 1)]
constant_part = 0
for _ in range(k):
p, c = map(int, input().split())
ships[p].append(c)
constant_part += c * (2 + p)
sum_cq = 0
overflow = []
for level in range(n, 0, -1):
overflow.extend(ships[level])
if len(overflow) <= m:
for c in overflow:
sum_cq += c * level
overflow.clear()
continue
overflow.sort(reverse=True)
for i in range(m):
sum_cq += overflow[i] * level
overflow = overflow[m:]
if overflow:
print(-1)
else:
print(constant_part - sum_cq)
main()
[sol-JavaScript]
const readline = require('readline');
const rl = readline.createInterface({ input: process.stdin });
const lines = [];
rl.on('line', line => lines.push(line.trim()));
rl.on('close', () => {
const [n, m, k] = lines[0].split(' ').map(Number);
const ships = Array.from({length: n + 1}, () => []);
let constantPart = 0;
for (let i = 1; i <= k; i++) {
const [p, c] = lines[i].split(' ').map(Number);
ships[p].push(c);
constantPart += c * (2 + p);
}
let sumCQ = 0;
let overflow = [];
for (let level = n; level >= 1; level--) {
overflow.push(...ships[level]);
if (overflow.length <= m) {
for (const c of overflow) {
sumCQ += c * level;
}
overflow = [];
continue;
}
overflow.sort((a, b) => b - a);
for (let i = 0; i < m; i++) {
sumCQ += overflow[i] * level;
}
overflow = overflow.slice(m);
}
if (overflow.length > 0) {
console.log(-1);
} else {
console.log(constantPart - sumCQ);
}
});
复杂度分析
- 时间复杂度:
,最坏情况下每层都需要对候选池排序。由于
,完全可以接受。
- 空间复杂度:
,存储各层星舰和溢出队列。

京公网安备 11010502036488号