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

1007: [HNOI2008]水平可见直线

题目:传送门

题解:

   蒟蒻在bzoj上做的第一道计算几何

   其实这道题并不难...(所以我A了)

   仔细想想不难发现,其实我们只需要维护一个下凸的图形...

   只有在这个图形上的直线才不会被覆盖,也就是可以被上帝直线看到的孩子

   为什么呢...自己画个图模拟吧。

   那么具体的做法我们就要采用单调栈啦!

   把给出的直线按照斜率从小到大排序(如果斜率相同的话就按照b来排)

   然后一个一个放入我们强大的单调栈中,在加入的同时我们当然还要进行维护:

   如果栈顶的直线与新加直线的交点在前一个的左边,那么就更新栈顶直线。

   很容易想到啊:一个下凸的图形,要求每条直线不被互相覆盖,那么不仅斜率递增,交点的横坐标也是不断增大的。

码个代码:

   

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

 

posted @ 2017-12-14 18:32  CHerish_OI  阅读(195)  评论(0编辑  收藏  举报