[BZOJ1007] [HNOI2008] 水平可见直线 (凸包)

Description

  在xoy直角坐标平面上有n条直线L1,L2,...Ln,若在y值为正无穷大处往下看,能见到Li的某个子线段,则称Li为可见的,否则Li为被覆盖的.

  例如,对于直线:L1:y=x; L2:y=-x; L3:y=0

  则L1和L2是可见的,L3是被覆盖的.

  给出n条直线,表示成y=Ax+B的形式(|A|,|B|<=500000),且n条直线两两不重合.求出所有可见的直线.

Input

  第一行为N(0 < N < 50000),接下来的N行输入Ai,Bi

Output

  从小到大输出可见直线的编号,两两中间用空格隔开,最后一个数字后面也必须有个空格

Sample Input

3
-1 0
1 0
0 0

Sample Output

1 2

HINT

Source

Solution

  按斜率从小到大给直线排序,维护一个下凸壳

  要把新加的线与凸壳的交点以右的直线删掉,因为新加的线一定在它与它之前的线组成的凸壳中

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 const double EPS = 1e-8;
 4 struct line
 5 {
 6     int id;
 7     double k, b;
 8     bool operator< (const line &rhs) const
 9     {
10         return fabs(k - rhs.k) < EPS ? b < rhs.b : k < rhs.k;
11     }
12 }a[100005];
13 int sta[100005], ans[100005];
14  
15 double getx(int x)
16 {
17     return (a[sta[x]].b - a[sta[x - 1]].b) / (a[sta[x - 1]].k - a[sta[x]].k);
18 }
19  
20 int main()
21 {
22     int n, top;
23     cin >> n;
24     for(int i = 1; i <= n; ++i)
25     {
26         cin >> a[i].k >> a[i].b;
27         a[i].id = i;
28     }
29     sort(a + 1, a + n + 1);
30     sta[top = 1] = 1;
31     for(int i = 2; i <= n; ++i)
32     {
33         sta[++top] = i;
34         while(top > 1)
35             if(fabs(a[i].k - a[sta[top - 1]].k) < EPS) sta[--top] = i;
36             else if(top > 2 && getx(top) - getx(top - 1) < EPS)
37                 sta[--top] = i;
38             else break;
39     }
40     for(int i = 1; i <= top; ++i)
41         ans[i] = a[sta[i]].id;
42     sort(ans + 1, ans + top + 1);
43     for(int i = 1; i <= top; ++i)
44         cout << ans[i] << ' ';
45     cout << endl;
46     return 0;
47 }
View Code

 

posted @ 2016-06-14 21:13  CtrlCV  阅读(510)  评论(0编辑  收藏  举报