贪心方法:"课程安排下找最多可以上多少节课"系列问题
类似问题还有:452、605、455、253等 直接秒杀!
一、问题概述
言归正传,本文解决一个很经典的贪心算法问题 Interval Scheduling
(区间调度问题)。给你很多形如 [start, end] 的闭区间,
请你设计一个算法,算出这些区间中最多有几个互不相交的区间。
二、贪心解法:
1. 从区间集合 intvs 中选择一个区间 x,这个 x 是在当前所有区间中结束最早的(end 最小)
2. 把所有与 x 区间相交的区间从区间集合 intvs 中删除
3. 重复步骤 1 和 2,直到 intvs 为空为止。之前选出的那些 x 就是最大不相交子集
为啥选择结束最早的,这里有解释:
labuladong
引用:labuladong
//sort()必须时静态成员函数
static bool cmp(vector<int> a, vector<int> b){
return a[1]<=b[1];
}
int intervalSchedule(vector<vector<int>>& intvs){
if(intvs.empty()) return 0;
// 按end升序排序
std::sort(intvs.begin(), intvs.end(), cmp);
// 至少有一个区间不相交
int count = 1;
// 排序后,第一个区间就是 x
int x_end = intvs[0][1];
for(int i = 1; i<intvs.size();i++){
int start = intvs[i][0];
// 当下一区间的star>=x_end时,说明没有交叉
if(start>=x_end){
// 找到下一个选择的区间了
count++;
x_end=interval[1];
}
}
return count; // count 就是最大不相交子集数
}
三、应用举例
第 435 题,无重叠区间:
我们已经会求最多有几个区间不会重叠了,那么剩下的
不就是至少需要去除的区间吗?
第 452 题,用最少的箭头射爆气球:
其实稍微思考一下,这个问题和区间调度算法一模一样!如果最多有 n 个不重叠的区间,那么就至少需要 n 个箭头穿透所有区间:
# sort的cmp函数传引用能加速,少了复制实参的过程
class Solution {
public:
static bool cmp(vector<int>& a, vector<int>& b){
return a[1]<=b[1];
}
// 找出多少个区间不重叠,就是需要的最小的弓箭数,因为重叠的用一根弓箭就可以了
int findMinArrowShots(vector<vector<int>>& points) {
if(points.empty()) return 0;
// 按end升序排序
std::sort(points.begin(), points.end(), cmp);
int count = 1;
// 第一个区间的end与后面区间的start比较
int x_end = points[0][1];
for(int i =1; i<points.size(); i++){
int start = points[i][0];
// start = end也算重叠
if(start>x_end){
count++;
x_end = points[i][1]; // 更新区间的end
}
}
return count;
}
};
贪心算法多机调度问题
#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
using namespace std;
int main()
{
int m, n;
while (cin >> m >> n)
{
vector<int> task(n);
for (int i = 0; i < n; i++)
cin >> task[i];
// 首先对任务处理时间排序
sort(task.begin(), task.end());
vector<int> cpu_queen(m);
for (int i = 0; i < n; i++)
{
cpu_queen[0] += task[i];
// 对任务处理队列排序,其实每次只需要调整第一个值,插入到后面,可以手写
sort(cpu_queen.begin(), cpu_queen.end());
}
cout << cpu_queen[m - 1] << endl; // 因为经过了排序,所以是最长耗时的机器为,处理完所有任务所需的时间
}
}