bzoj1007[HNOI2008]水平可见直线

Posted lazytear

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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

题解

 这道题的想法还算比较清晰。首先将每条边按照斜率排序,用一个栈维护。每一次如果栈顶直线平行于新的直线或者新的直线和栈中第二条直线的交点在栈顶直线和栈中第二条直线的交点的左边,则弹出栈顶元素,因为新的直线的斜率一定比栈顶直线的斜率大,新的交点若在旧的交点的左边,则栈顶的直线显露出来的部分一定会被新的直线完全覆盖,因此可以这么做。

代码:

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

 

 

 

以上是关于bzoj1007[HNOI2008]水平可见直线的主要内容,如果未能解决你的问题,请参考以下文章

bzoj 1007 [HNOI2008]水平可见直线(单调栈)

BZOJ 1007: [HNOI2008]水平可见直线

BZOJ 1007: [HNOI2008]水平可见直线

bzoj1007: [HNOI2008]水平可见直线

bzoj 1007: [HNOI2008]水平可见直线

bzoj1007: [HNOI2008]水平可见直线(单调栈)