bzoj1007 [HNOI2008]水平可见直线

Description

Input

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

Output

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

Sample Input

3
-1 0
1 0
0 0

Sample Output

1 2

题解

算法比较直观,先按斜率排序,再将最小的两条线入栈,然后依次处理每条线,如果其与栈顶元素的交点在上一个点的左边,则将栈顶元素出栈 ;这样为什么对呢?因为对如任意一个开口向上的半凸包,从左到右依次观察每条边和每个顶点,发现其斜率不断增大,顶点的横坐标也不断增大。

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cmath>
 4 #include<iostream>
 5 #include<cstring>
 6 #define eps 0.0000001
 7 using namespace std;
 8 
 9 int top,n;
10 bool boo[50007];
11 struct Node
12 {
13     double x,y;
14     int num;
15 }a[50007],stack[50007];
16 
17 double rope(Node x,Node y)
18 {
19     return (y.y-x.y)/(x.x-y.x);
20 }
21 bool cmp(Node x,Node y)
22 {
23     if (fabs(x.x-y.x)<eps) return x.y<y.y;
24     else return x.x<y.x;
25 }
26 void solve()
27 {
28     for (int i=1;i<=n;i++)
29     {
30         while(top)
31         {
32             if (fabs(stack[top].x-a[i].x)<=eps) top--;//后者b大 
33             else if (top>1&&rope(a[i],stack[top-1])<=rope(stack[top],stack[top-1])) top--;
34             else break;
35         }
36         stack[++top]=a[i];
37     }
38     for (int i=1;i<=top;i++)
39         boo[stack[i].num]=1;
40     for (int i=1;i<=n;i++)
41         if (boo[i]) printf("%d ",i);    
42 }
43 int main()
44 {
45     scanf("%d",&n);
46     for (int i=1;i<=n;i++)
47     {
48         scanf("%lf%lf",&a[i].x,&a[i].y);
49         a[i].num=i;
50     }
51     sort(a+1,a+n+1,cmp);
52     solve();
53 }
原文地址:https://www.cnblogs.com/fengzhiyuan/p/7766250.html