zoukankan      html  css  js  c++  java
  • 【BZOJ1007】【HNOI2008】水平可见直线(斜率排序+单调栈)

    1007: [HNOI2008]水平可见直线

    Time Limit: 1 Sec  Memory Limit: 162 MB
    Submit: 2605  Solved: 914
    [Submit][Status]

    Description

    Input

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

    Output

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

    Sample Input

    3
    -1 0
    1 0
    0 0

    Sample Output

    1 2

    HINT

     

    Source

    分析:本蒟残还是太弱,只能膜拜题解:

    以下摘自wyl大神的空间:http://hi.baidu.com/wyl8899/item/061d3b0de2c42b344bc4a362

    正解是按斜率排序,用栈维护可见直线。

    如右图,当前考虑直线now,栈顶top,栈顶的下一个元素top'大致的位置。

    显然now和top'将把top完全遮盖。

    思考一下可以得出,记两直线交点的横坐标为x(A,B),则x(now,top)<=x(top,top')时,栈顶直线被废,弹出栈。

    反复这样操作,直至不满足上面的条件,将当前直线压入栈中。

    最后在栈中的直线就是答案。

    对了,同斜率的直线,显然只考虑截距最大的那个就好了,因此要处理一下(当然不处理的话x(now,top)的计算过程中要divided by 0)

     

     

    总结:一般情况下处理多条直线的问题都是将它们按照斜率排序(我发现很多直线题这一步都是基础),而且之后就能用单调性维护(这个也经常见到,比如斜率优化dp里面就是用单调队列,本题用单调栈)

    code:

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 #include<cmath>
     5 using namespace std;
     6 const int maxn=50000;
     7 struct wjmzbmr
     8 {
     9     int k,b,w;
    10     bool operator < (const wjmzbmr& x) const 
    11     {
    12         return (k<x.k)||((k==x.k)&&(b>x.b));
    13     }
    14 }a[maxn+50];
    15 wjmzbmr c[maxn+50];
    16 int n,stack[maxn+50],b[maxn+50];
    17 bool f[maxn+50];
    18 bool pd(int now,int top,int ltop)
    19 {
    20     double x1=(double)(c[top].b-c[now].b)/(double)(c[now].k-c[top].k);
    21     double x2=(double)(c[top].b-c[ltop].b)/(double)(c[ltop].k-c[top].k);
    22     if(x2-x1>=0.0) return true;else return false;
    23 }
    24 int main()
    25 {
    26     freopen("ce.in","r",stdin);
    27     freopen("ce.out","w",stdout);
    28     scanf("%d",&n);
    29     for(int i=0;i<n;++i) 
    30     {
    31         scanf("%d%d",&a[i].k,&a[i].b);
    32         a[i].w=i;
    33         c[i]=a[i];
    34     }
    35     sort(a,a+n);
    36     int size=0;b[size]=a[0].w;
    37     for(int i=1;i<n;++i) if(a[i].k!=a[i-1].k) b[++size]=a[i].w;
    38     int len=1;
    39     memset(stack,0,sizeof(stack));
    40     stack[0]=b[0],stack[1]=b[1];
    41     for(int i=2;i<=size;++i)
    42     {
    43         while(len>=1&&pd(b[i],stack[len],stack[len-1])) --len;
    44         stack[++len]=b[i];
    45     }
    46     memset(f,0,sizeof(f));
    47     for(int i=0;i<=len;++i) f[stack[i]]=1;
    48     for(int i=0;i<n;++i) if(f[i]==1) printf("%d ",i+1);
    49     return 0;
    50 }
    View Code
  • 相关阅读:
    踩踩踩
    c语言可变参
    C++开发者都应该使用的10个C++11特性
    c++11 条件变量 生产者-消费者 并发线程
    c++11 线程
    C++ 虚函数表解析 继承
    坐标系
    C++ 容器:顺序性容器、关联式容器和容器适配器
    全面深入介绍C++字符串:string类
    做一个懒COCOS2D-X程序猿(一)停止手打所有cpp文件到android.mk
  • 原文地址:https://www.cnblogs.com/wmrv587/p/3500400.html
Copyright © 2011-2022 走看看