[HNOI2008]水平可见直线

题目描述

在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条直线两两不重合.求出所有可见的直线.

输入输出格式

输入格式:

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

输出格式:

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

输入输出样例

输入样例#1: 复制
3
-1 0
1 0
0 0
输出样例#1: 复制
1 2
实际上就是求一个最长下凸包
没有学过计蒜几何也没关系,可以自己画图理解
按斜率从小到大排序
实际上考虑两种情况:
1.

这种情况显然可以,就是一个下凸包

2.

 

这样显然斜率第2的直线无法看到

这样我们可以发现

如果i>j>k

交点(i,k)在交点(j,k)左边,那么j就不行

于是用单调栈

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<cmath>
 6 using namespace std;
 7 struct Node
 8 {
 9   double a,b;
10   int n;
11 }a[50001];
12 int n,top,s[50001];
13 double p1,p2,eps=1e-8;
14 double cross(int i,int j)
15 {
16   double x=(a[j].b-a[i].b)/(a[i].a-a[j].a);
17   return x;
18 }
19 bool cmp(Node a,Node b)
20 {
21   if (fabs(a.a-b.a)<eps) return a.b<b.b;
22   return a.a<b.a;
23 }
24 int main()
25 {int i,j;
26   cin>>n;
27   for (i=1;i<=n;i++)
28     {
29       scanf("%lf%lf",&a[i].a,&a[i].b);
30       a[i].n=i;
31     }
32   sort(a+1,a+n+1,cmp);
33   for (i=1;i<=n;i++)
34     {
35       while (top)
36       {
37         if (fabs(a[i].a-a[s[top]].a)<eps) top--;
38     else if (top>1&&cross(i,s[top-1])<=cross(s[top-1],s[top])) top--;
39     else break;
40       }
41       s[++top]=i;
42     }
43   for (i=1;i<=top;i++)
44     s[i]=a[s[i]].n;
45   sort(s+1,s+top+1);
46   for (i=1;i<=top;i++)
47     printf("%d ",s[i]);
48 }

 

posted @ 2017-12-24 21:08  Z-Y-Y-S  阅读(284)  评论(0编辑  收藏  举报