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

Solution

首先把直线按照斜率排序,再用个栈维护一下。

画个图可以发现,如果直线$i$和直线$stack[top]$的交点在直线$stack[top-1]$的左边,那么$stack[top]$就可以被弹出了。随便判判就好了。

Code

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<algorithm>
 5 #define N (50009)
 6 #define INF (1e18)
 7 using namespace std;
 8 
 9 struct Vector
10 {
11     double x,y;
12     Vector(double xx=0,double yy=0)
13     {
14         x=xx; y=yy;
15     }
16 }p[N];
17 typedef Vector Point;
18 
19 struct Line
20 {
21     double k,b;
22     Point x,y;
23     int id;
24     bool operator < (const Line &a) const
25     {
26         return k==a.k?b>a.b:k>a.k;
27     }
28     bool operator == (const Line &a) const
29     {
30         return k==a.k && b==a.b;
31     }
32 }L[N],stack[N];
33 
34 int n,k,b,ans[N],top;
35 
36 double Cross(Vector a,Vector b) {return a.x*b.y-a.y*b.x;}
37 Vector operator - (Vector a,Vector b) {return Vector(a.x-b.x,a.y-b.y);}
38 
39 inline int read()
40 {
41     int x=0,w=1; char c=getchar();
42     while (!isdigit(c)) {if (c=='-') w=-1; c=getchar();}
43     while (isdigit(c)) x=x*10+c-'0', c=getchar();
44     return x*w;
45 }
46 
47 Point Line_Cross(Line u,Line v)
48 {
49     Point ans;
50     ans.x=(v.b-u.b)/(u.k-v.k);
51     ans.y=u.k*ans.x+u.b;
52     return ans;
53 }
54 
55 int main()
56 {
57     n=read();
58     for (int i=1; i<=n; ++i)
59     {
60         k=read(); b=read();
61         L[i]=(Line){k,b};
62         L[i].x=(Point){0,b};
63         L[i].y=(Point){1,k+b};
64         L[i].id=i;
65     }
66     sort(L+1,L+n+1);
67     for (int i=1; i<=n; ++i)
68     {
69         if (top && L[i].k==stack[top].k) continue;
70         while (top>=2)
71         {
72             Point p=Line_Cross(stack[top],L[i]);
73             if (Cross(stack[top-1].x-p,stack[top-1].y-p)>0) break;
74             top--;
75         }
76         stack[++top]=L[i];
77     }
78     for (int i=1; i<=top; ++i) ans[stack[i].id]=1;
79     for (int i=1; i<=n; ++i) if (ans[i]) printf("%d ",i);
80 }
posted @ 2019-03-01 10:11  Refun  阅读(185)  评论(0编辑  收藏  举报