某公司组织一场公开招聘活动,假设由于人数和场地的限制,每人每次面试的时长不等,并已经安排给定,用(S1,E1)、 (S2,E2)、 (Sj,Ej)…(Si < Ei,均为非负整数)表示每场面试的开始和结束时间。
面试采用一对一的方式,即一名面试官同时只能面试一名应试者,一名面试官完成一次面试后可以立即进行下一场面试,且每个面试官的面试人次不超过 m。
为了支撑招聘活动高效顺利进行,请你计算至少需要多少名面试官
接下来的 n 行为每场面试的起始时间和结束时间,起始时间和结束时间用空格分隔。
其中, 1 <= n, m <= 500
2
5
1 2
2 3
3 4
4 5
5 6
3
3
3
1 2
2 3
3 4
1
3
3
8 35
5 10
1 3
2
给定两个整数 m 和 n,m 表示每个池子(或资源)最多可以容纳的任务数量,n 表示任务的总数。
接着输入 n 行数据,每行包含两个整数 s 和 e,表示一个任务的开始时间 s 和结束时间 e。
目标是将所有任务分配到若干个池子中,满足以下条件:
每个池子最多容纳 m 个任务。
同一个池子中的任务不能时间重叠,即后一个任务的开始时间必须大于等于前一个任务的结束时间。
核心思路:
按结束时间排序:为了尽量多地安排任务,优先安排最早结束的任务。
分配任务到池子:遍历排序后的任务列表,将每个任务依次分配到满足条件的池子中:
如果当前池子未满且最后一个任务的结束时间小于等于当前任务的开始时间,则将该任务放入此池子。
如果没有找到合适的池子,则继续检查下一个池子。
统计池子数量:最终统计非空池子的数量,即为所需的池子数
# 读取池子的最大任务数m和任务总数n
m = int(input())
n = int(input())
# 读取n个任务的开始时间和结束时间,存入data列表
data = [list(map(int, input().split())) for _ in range(n)]
def calc():
# 按任务的结束时间升序排序,以便尽可能早地安排任务
data.sort(key=lambda x: x[1])
# 初始化池子列表,每个池子是一个列表,用于存放任务的结束时间
pools = [[] for _ in range(n)]
i = 0
# 遍历每个任务
while i < len(data):
s, e = data[i] # 当前任务的开始时间s和结束时间e
j = 0
# 尝试将任务分配到某个池子中
while j < len(pools):
# 检查当前池子是否有空间,并且任务时间是否不冲突
if len(pools[j]) < m and (len(pools[j]) == 0 or pools[j][-1] <= s):
pools[j].append(e) # 将任务的结束时间加入池子
break # 成功放入池子后,跳出循环
j += 1 # 检查下一个池子
i += 1 # 处理下一个任务
# 统计非空池子的数量,表示总共用了多少个池子
return len([p for p in pools if len(p) > 0])
# 输出所需的池子数量
print(calc())
输入包括两个整数 m 和 n:
m 表示每个池子(或资源)最多可以容纳的任务数量。
n 表示任务的总数。
接下来输入 n 行,每行包含两个整数,分别表示任务的开始时间 s 和结束时间 e。
目标是将所有任务分配到若干个池子中,满足以下条件:
每个池子最多容纳 m 个任务。
同一个池子中的任务不能时间重叠,即后一个任务的开始时间必须大于等于前一个任务的结束时间。
最终输出所需的最少池子数量。
算法思路:
排序任务:首先按任务的结束时间升序排序,以便尽可能早地安排任务,从而减少池子的使用。
分配任务到池子:
遍历每个任务,尝试将其放入已存在的池子中。
如果当前池子未满,且池子中最后一个任务的结束时间小于等于当前任务的开始时间,则将任务放入该池子。
如果没有找到合适的池子,说明需要新开一个池子。
统计池子数量:最后统计非空池子的数量,得到所需的池子数
import java.util.*;
public class Main {
// 计算所需池子数量的方法
public static int calc(int m, int n, int[][] data) {
// 按任务的结束时间升序排序,以便尽可能早地安排任务
Arrays.sort(data, Comparator.comparingInt(a -> a[1]));
// 初始化池子列表,每个池子是一个存储任务结束时间的列表
List<List<Integer>> pools = new ArrayList<>();
for (int i = 0; i < n; i++) {
pools.add(new ArrayList<>()); // 最多创建n个池子
}
// 遍历每个任务
for (int i = 0; i < data.length; i++) {
int s = data[i][0]; // 任务的开始时间
int e = data[i][1]; // 任务的结束时间
boolean added = false; // 标记任务是否成功分配到池子
// 尝试将任务放入现有池子
for (List<Integer> pool : pools) {
// 检查池子是否未满,且当前任务时间不与池子中的任务冲突
if (pool.size() < m && (pool.isEmpty() || pool.get(pool.size() - 1) <= s)) {
pool.add(e); // 将任务的结束时间添加到池子中
added = true; // 标记任务已成功分配
break; // 找到合适的池子后,跳出循环
}
}
// 如果没有找到合适的池子,说明任务无法分配(按题意不会出现这种情况)
if (!added) {
break;
}
}
// 统计非空池子的数量,即为所需池子数量
int count = 0;
for (List<Integer> pool : pools) {
if (!pool.isEmpty()) {
count++;
}
}
return count;
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// 读取池子的最大任务数m和任务总数n
int m = scanner.nextInt();
int n = scanner.nextInt();
int[][] data = new int[n][2]; // 用于存储每个任务的开始和结束时间
// 读取每个任务的时间
for (int i = 0; i < n; i++) {
data[i][0] = scanner.nextInt(); // 任务的开始时间
data[i][1] = scanner.nextInt(); // 任务的结束时间
}
// 调用计算方法并输出所需池子数量
System.out.println(calc(m, n, data));
scanner.close(); // 关闭输入流
}
}
更新中
题目理解:
输入两个整数 m 和 n:
m:每个池子最多可以容纳的任务数量。
n:总共有 n 个任务。
接下来输入 n 行,每行包含两个整数,表示任务的开始时间 start 和结束时间 end。
任务需要分配到若干个池子中,满足以下条件:
每个池子最多容纳 m 个任务。
同一个池子中的任务不能有时间重叠,即后一个任务的开始时间必须大于等于前一个任务的结束时间。
目标是计算并输出所需的最少池子数量。
算法思路:
按结束时间排序:为了尽量减少池子的使用,先将任务按结束时间升序排序,优先安排结束时间早的任务。
分配任务到池子:
遍历每个任务,尝试将其放入已存在的池子中。
如果池子未满,且池子中最后一个任务的结束时间小于等于当前任务的开始时间,则将任务放入该池子。
如果没有找到合适的池子,则新开一个池子。
统计池子数量:最后统计非空池子的数量,即为所需池子的数量
#include
#include
// 定义任务区间结构体,包含开始时间和结束时间
typedef struct {
int start;
int end;
} Interval;
// 比较函数:按任务的结束时间升序排序
int compareIntervals(const void* a, const void* b) {
Interval* interval1 = (Interval*)a;
Interval* interval2 = (Interval*)b;
return interval1->end - interval2->end;
}
// 计算所需池子数量的函数
int calculatePools(int m, int n, Interval* intervals) {
// 将任务按结束时间排序,方便优先安排早结束的任务
qsort(intervals, n, sizeof(Interval), compareIntervals);
// 初始化池子,每个池子存储任务的结束时间
int pools[MAX_POOLS][MAX_N] = { 0 }; // pools[i][j] 表示第 i 个池子的第 j 个任务的结束时间
int poolSizes[MAX_POOLS] = { 0 }; // 记录每个池子当前的任务数量
int poolCount = 0; // 当前池子的数量
// 遍历每个任务,尝试分配到合适的池子
for (int i = 0; i < n; i++) {
int start = intervals[i].start; // 当前任务的开始时间
int end = intervals[i].end; // 当前任务的结束时间
int added = 0; // 标记当前任务是否已成功分配到池子
// 尝试将任务放入已存在的池子中
for (int j = 0; j < poolCount; j++) {
// 检查池子是否未满,且任务时间不冲突
if (poolSizes[j] < m && (poolSizes[j] == 0 || pools[j][poolSizes[j] - 1] <= start)) {
pools[j][poolSizes[j]++] = end; // 将任务的结束时间放入池子
added = 1; // 标记任务已分配
break; // 找到合适的池子后退出循环
}
}
// 如果没有合适的池子,创建新池子
if (!added) {
pools[poolCount][poolSizes[poolCount]++] = end; // 新池子存放当前任务
poolCount++; // 池子数量加一
}
}
// 返回池子的总数量
return poolCount;
}
int main() {
int m, n;
scanf("%d %d", &m, &n); // 读取池子的最大容量m和任务数量n
Interval intervals[MAX_N]; // 存储任务的开始和结束时间
for (int i = 0; i < n; i++) {
scanf("%d %d", &intervals[i].start, &intervals[i].end); // 读取每个任务
}
// 计算并输出所需池子数量
int result = calculatePools(m, n, intervals);
printf("%d\n", result);
return 0;
}
题目理解:
输入包括两个整数 m 和 n:
m 表示每个池子(或资源)最多可以容纳的任务数量。
n 表示任务的总数。
接下来输入 n 行,每行包含两个整数,表示任务的开始时间 start 和结束时间 end。
任务需要分配到若干个池子中,满足以下条件:
同一个池子中的任务不能有时间重叠,即后一个任务的开始时间必须大于等于前一个任务的结束时间。
每个池子最多容纳 m 个任务(不过代码中并未处理这个条件)。
最终目标是计算所需的最少池子数量。
算法思路:
按任务开始时间排序:首先将任务按开始时间升序排序,若开始时间相同,再按结束时间升序排序。
使用最小堆(优先队列)模拟池子分配:
heap 数组存储当前每个池子的最新结束时间。
遍历任务列表,尝试将当前任务分配到已有的池子中:
如果最早结束的池子(即 heap 中的最小值)结束时间小于等于当前任务的开始时间,则表示该池子可以容纳当前任务,更新该池子的结束时间。
如果没有找到合适的池子,则新开一个池子,将当前任务的结束时间加入 heap。
每次操作后,重新排序 heap,确保最早结束的池子在最前面。
统计池子数量:遍历完所有任务后,heap 的长度即为所需的最少池子数量
const readline = require("readline");
// 创建输入输出接口
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
const lines = []; // 存储输入数据
let m, n; // m: 每个池子的最大任务数, n: 任务数量
// 读取输入数据
rl.on("line", (line) => {
lines.push(line); // 每行输入存入数组
// 读取前两行,分别为 m 和 n
if (lines.length === 2) {
m = parseInt(lines[0]); // 每个池子的最大任务数量
n = parseInt(lines[1]); // 任务数量
}
// 当所有任务输入完毕后,调用计算函数
if (n && lines.length === n + 2) {
const ranges = lines.slice(2).map((line) => line.split(" ").map(Number)); // 解析任务的开始和结束时间
console.log(getResult(ranges, m, n)); // 输出结果
lines.length = 0; // 清空输入数组,准备读取下一组数据(如果有)
}
});
// 计算所需池子数量的函数
function getResult(ranges, m, n) {
// 按任务的开始时间升序排序,若开始时间相同,则按结束时间升序排序
ranges.sort((a, b) => a[0] - b[0] || a[1] - b[1]);
const heap = []; // 最小堆,存储每个池子的最新结束时间
// 遍历每个任务,尝试分配到池子
for (let [start, end] of ranges) {
let assigned = false; // 标记任务是否已分配到池子
// 如果最早结束的池子结束时间 <= 当前任务的开始时间,表示可以复用该池子
if (heap.length && heap[0] <= start) {
heap.shift(); // 移除最早结束的池子(表示该池子已分配当前任务)
heap.push(end); // 将当前任务的结束时间放入池子
assigned = true;
}
// 如果没有合适的池子,创建新池子
if (!assigned) {
heap.push(end);
}
// 重新排序堆,确保最早结束的池子在最前面
heap.sort((a, b) => a - b);
}
return heap.length; // 返回池子的数量
}
如果发现代码有用例覆盖不到的情况,欢迎反馈!会在第一时间修正,更新。
解题不易,如对您有帮助,欢迎点赞/收藏