这是个典型的线程服务区间模型。一些程序要在一段时间区间上使用一段线程运行,问至少要使用多少线程来为这些程序服务?
把所有程序以左端点为第一关键字,右端点为第二关键字从小到大排序。从左向右扫描。处理当前区间时,提取出所有线程中最后一个被服务中的区间中右端点最小的区间(可用小根堆实现),若当前区间左端点值大于提取出的区间的右端点的值,则把当前区间安排到选中的区间的那个线程,否则只能再派出一个线程来负责该区间了。
此贪心是正确的,因为正在被服务中的区间中右端点最小的区间,能使当前区间不被该线程负责的当前区间左端点范围最小。
注意:
- 右端点为第二关键字。
- 题中的时间点其实不是点,而是个格子,所以是“当前区间左端点值【大于】提取出的区间的右端点的值”,而不是【大于等于】。
#include <cstdio> #include <iostream> #include <cstring> #include <algorithm> #include <queue> using namespace std; const int MAX_RANGE_CNT = 50010; struct Line { int End, Id; bool operator < (const Line a) const { return End > a.End; } Line() {} Line(int id, int end):Id(id),End(end){} }; priority_queue<Line> Heap; struct Range { int L, R, TargetLineId; }_ranges[MAX_RANGE_CNT], *_sortedRanges[MAX_RANGE_CNT]; bool cmp(Range *a, Range *b) { if (a->L != b->L) return a->L < b->L; else return a->R < b->R; } int main() { int rangeCnt; scanf("%d", &rangeCnt); for (int i = 1; i <= rangeCnt; i++) scanf("%d%d", &_ranges[i].L, &_ranges[i].R); for (int i = 1; i <= rangeCnt; i++) _sortedRanges[i] = _ranges + i; sort(_sortedRanges + 1, _sortedRanges + rangeCnt + 1, cmp); int lineCnt = 0; for (int i = 1; i <= rangeCnt; i++) { Range *cur = _sortedRanges[i]; if (!Heap.empty() && Heap.top().End < cur->L) { Line prev = Heap.top(); cur->TargetLineId = prev.Id; Heap.pop(); Heap.push(Line(prev.Id,cur->R)); } else { lineCnt++; cur->TargetLineId = lineCnt; Heap.push(Line(lineCnt, cur->R)); } } printf("%d ", lineCnt); for (int i = 1; i <= rangeCnt; i++) printf("%d ", _ranges[i].TargetLineId); return 0; }