標籤:acm
題目連結
- 題意:
輸入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;}