云服务资源调度
题意
有 个任务,每个任务有一个计算成本
。服务器的最大计算容量为
。为每台服务器分配任务时,采用贪心策略:总是优先选择当前未分配的、计算成本最高的、且不超出剩余容量的任务。问处理完所有任务最少需要多少台服务器。
思路
题目描述的其实是一个确定性的装箱模拟:每开一台新服务器,就从剩余任务中反复挑最大的能放进去的,直到再也放不进,然后开下一台。
具体流程:
- 把任务按成本从大到小排序。
- 遍历任务,遇到第一个还没被分配的任务,就开一台新服务器,把这个任务放进去。
- 接着从剩余任务中扫描,每次挑最大的且不超出剩余容量的任务放进去,直到没有能放的为止。
- 重复 2-3 直到所有任务都被分配。
有一个容易踩的坑:任务的计算成本可能超过服务器容量 。这种任务无法和别的任务拼在一起,但仍然需要占一台服务器。如果在代码里先设
remaining = c 再扫描,超过 的任务永远不满足
cost <= remaining,就会被漏掉。正确的做法是:开服务器时先把这个任务"强制放入"(used[i] = true, remaining = c - cost[i]),这样即使 remaining 变成负数,该任务也不会被遗漏。
为什么排序后从大到小开服务器、然后向小端扫描是对的?
因为大任务"挤占"容量多,越早安排越好。大任务开了一台服务器之后,剩余空间只能塞比它小的任务。从大到小扫描,遇到第一个能放进去的就是"最大的能放进去的",符合题目的贪心规则。
拿样例验证一下:容量 ,排序后
。
| 服务器 | 放入任务 | 使用容量 |
|---|---|---|
| 1 | 98, 9 | 107 |
| 2 | 98, 8 | 106 |
| 3 | 78, 32 | 110 |
| 4 | 73, 31 | 104 |
| 5 | 54, 51 | 105 |
| 6 | 46, 44 | 90 |
| 7 | 27 | 27 |
一共 7 台,和答案一致。
复杂度
- 时间:
,排序
,模拟最坏情况每台服务器扫描一遍数组
- 空间:
代码
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
cin >> n;
vector<long long> costs(n);
for (int i = 0; i < n; i++) cin >> costs[i];
long long c;
cin >> c;
sort(costs.begin(), costs.end());
vector<bool> used(n, false);
int servers = 0;
for (int i = n - 1; i >= 0; i--) {
if (used[i]) continue;
servers++;
used[i] = true;
long long remaining = c - costs[i];
for (int j = i - 1; j >= 0; j--) {
if (!used[j] && costs[j] <= remaining) {
used[j] = true;
remaining -= costs[j];
if (remaining == 0) break;
}
}
}
cout << servers << endl;
return 0;
}
import java.util.*;
import java.io.*;
public class Main {
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StreamTokenizer st = new StreamTokenizer(br);
st.nextToken(); int n = (int) st.nval;
long[] costs = new long[n];
for (int i = 0; i < n; i++) {
st.nextToken();
costs[i] = (long) st.nval;
}
st.nextToken(); long c = (long) st.nval;
Arrays.sort(costs);
boolean[] used = new boolean[n];
int servers = 0;
for (int i = n - 1; i >= 0; i--) {
if (used[i]) continue;
servers++;
used[i] = true;
long remaining = c - costs[i];
for (int j = i - 1; j >= 0; j--) {
if (!used[j] && costs[j] <= remaining) {
used[j] = true;
remaining -= costs[j];
if (remaining == 0) break;
}
}
}
System.out.println(servers);
}
}
import sys
def solve():
input_data = sys.stdin.read().split()
idx = 0
n = int(input_data[idx]); idx += 1
costs = []
for i in range(n):
costs.append(int(input_data[idx])); idx += 1
c = int(input_data[idx]); idx += 1
costs.sort()
used = [False] * n
servers = 0
for i in range(n - 1, -1, -1):
if used[i]:
continue
servers += 1
used[i] = True
remaining = c - costs[i]
for j in range(i - 1, -1, -1):
if not used[j] and costs[j] <= remaining:
used[j] = True
remaining -= costs[j]
if remaining == 0:
break
print(servers)
solve()
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 = parseInt(lines[0]);
const costs = lines[1].split(/\s+/).map(Number);
const c = parseInt(lines[2]);
costs.sort((a, b) => a - b);
const used = new Array(n).fill(false);
let servers = 0;
for (let i = n - 1; i >= 0; i--) {
if (used[i]) continue;
servers++;
used[i] = true;
let remaining = c - costs[i];
for (let j = i - 1; j >= 0; j--) {
if (!used[j] && costs[j] <= remaining) {
used[j] = true;
remaining -= costs[j];
if (remaining === 0) break;
}
}
}
console.log(servers);
});

京公网安备 11010502036488号