- 题意:
输入n个左闭右开的线段,如果两个线段有重叠部分,那么这两个线段必然不能在一组。求,最少分几组,并且输出每组都有谁
- 分析:
将一个线段拆开成左右端点,排序。从左向右扫描,如果遇到的是左端点,那么直接加入到集合中,此时集合中的这些线段两两有重合部分,所以是可以分到同一组的;如果遇到的是右端点,那么当前线段之后将和当前线段没有重合点,必然不能放到一组。这样贪心的将每一个线段尽可能的分到一个组中(分到哪个组无所谓,只要分到了一个组中,答案就能减少),就可以保证答案是最少的。当一个线段不能分到前一个组中,必然是和前一个组中的某条线段冲突,所以保证了正确性。
const int MAXN = 1100000; struct Node { int v, id, isr; int operator< (const Node& rhs) const { if (v != rhs.v) return v < rhs.v; else return isr > rhs.isr; } } ipt[MAXN]; VI ans[MAXN]; int vis[MAXN]; int main() { int n, l, r; while (~RI(n)) { CLR(vis, 0); REP(i, MAXN) ans[i].clear(); REP(i, n) { RII(l, r); int x = i << 1, y = x | 1; ipt[x].isr = 0; ipt[x].v = l; ipt[y].isr = 1; ipt[y].v = r; ipt[x].id = ipt[y].id = i + 1; } n <<= 1; sort(ipt, ipt + n); int val = 0; REP(i, n) { if (ipt[i].isr) { if (vis[ipt[i].id] != val) continue; val++; } else { ans[val].push_back(ipt[i].id); vis[ipt[i].id] = val; } } WI(val); REP(i, val) REP(j, ans[i].size()) printf("%d%c", ans[i][j], j == (int)ans[i].size() - 1 ? '\n' : ' '); } return 0; }
Final Exam Arrangement,布布扣,bubuko.com
时间: 2025-01-08 21:49:33