Bzoj P1007 [HNOI2008]水平可见直线___单调栈+思维

题目大意:

给出n条直线,表示成y=Ax+B的形式,且n条直线两两不重合.求出所有可见的直线。

|A|,|B|<=500000

分析:

这题在图上画一下可以发现一个很显然的做法,
对于当前一条斜率最大跟一条斜率次大的直线的交点为[x,y],如果我们加入一条斜率比这两条都大的,且与次大的直线的交点为[x1,y1],
那么当x1 <= x 时,当前斜率最大的直线就会被覆盖

基于这么一个思想,我们将斜率排序以后就可以依次加入栈然后不断的维护这么一个单调栈
最后还在栈中的直线则是可见的

代码:


#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
#include<cmath>
#define N 50005

using namespace std;

const double eps = 1e-8;

struct node{
    double k,b;
    int id;
}a[N];
int Q[N],f[N],n;

bool cmp(node aa, node bb){
    if (fabs(aa.k-bb.k) <= eps) return aa.b > bb.b;
    return aa.k < bb.k;
}

double getx(int x, int y){
    return (a[y].b - a[x].b) / (a[x].k - a[y].k);
}

int main()
{
    scanf("%d",&n);
    for (int i = 1; i <= n; i++){
         scanf("%lf%lf",&a[i].k,&a[i].b);
         a[i].id = i;
    }
    sort(a+1,a+n+1,cmp);

    Q[1] = 1;
    int head = 1,tail = 1;
    int rp = 2;
    while (rp <= n){
           if (a[rp].k != a[Q[tail]].k){
               while (tail > head){
                      double x1 = getx(rp, Q[tail-1]);
                      double x2 = getx(Q[tail-1], Q[tail]);
                      if (x1 <= x2) tail--;
                               else break;
               }
               Q[++tail] = rp;
           } 
           rp++;    
    }
    for (int i = head; i <= tail; i++) f[a[Q[i]].id] = 1;
    for (int i = 1; i <= n; i++) 
         if (f[i]) printf("%d ",i);
    printf("\n");
    return 0;
}


猜你喜欢

转载自blog.csdn.net/gx_man_vip/article/details/80255499