【算法学习笔记】51. 贪心法 区间排序问题 SJTU OJ 1360 偶像丁姐的烦恼
Description
成为LL冠军的人气偶像丁姐最近比较烦,许多商业活动找上门来。因为每次商业活动给的毛爷爷都一样,所以丁姐希望能够尽可能多的参加这些活动。然而,商业活动的起止时间并不由丁姐说了算,因此丁姐想写一个程序,求出他最多能够参加的商业活动的数量。
Input Format
第一行一个数n,表示可选活动的数量。
接下n行每行两个数,表示每个活动开始时间t1_i和结束的时间t2_i。
Output Format
一个数字,表示丁姐最多能够参加的活动的数量。
Sample Input
10
0 3
0 5
10 13
12 15
2 6
4 8
9 11
13 18
14 16
15 20
Sample Output
5
Hint
样例选取的活动时间为:(0, 3), (4, 8), (9, 11), (12, 15), (15, 20)
n≤100000
0≤t1_i<t2_i≤1000000
思路1.按左端排序 (同左则按右)
错误代码如下:
#include <iostream> #include <algorithm> using namespace std; struct Period { int start; int end; }; //按照start排序 int cmp_period(const void* _a, const void* _b){ Period* a = (Period*) _a; Period* b = (Period*) _b; if((*a).start != (*b).start) return (*a).start - (*b).start; else return (*a).end - (*b).end; } Period ps[100001]; int main(int argc, char const *argv[]) { int n; cin>>n; for (int i = 0; i < n; ++i){ cin>>ps[i].start>>ps[i].end; } qsort(ps,n,sizeof(Period),cmp_period); // for (int i = 0; i < n; ++i) // { // cout<<ps[i].start<<" "<<ps[i].end<<endl; // } int cur = ps[0].start; int index = 0; int ans = 1; while(1){ cur = ps[index].end; index++; for(;index < n; index++){ if(ps[index].start >= cur){ if(index<n-1 and ps[index+1].end < ps[index].end) index++; ans++; break; } } if(index >= n-1) break; } cout<<ans<<endl; return 0; }
样例经过排序后则是
0 3
0 5
2 6
4 8
9 11
10 13
12 15
13 18
14 16
15 20
第一直觉是先选择第一个区间,然后选择左端点大于等于第一个区间右端点的第一个区间,(4,8) 然后以此类推。因为同样的起点里,肯定选择的是尾部更小的。
但是这种方法会产生一个问题就是,遇到了完全重合区间没有办法延伸。
比如
0 3
3 9
4 8
8 9
按刚才的算法回选择 0 3, 3 9 但是实际上应该是 0 3, 4 8, 8 9
原因在于4,8是完全含于3,9的,所以我们要选择4,8并继续进行下去