洛谷P3194 [HNOI2008]水平可见直线(计算几何+单调栈)

原题链接
思路:
答案是最上面的一些直线,借助于求凸包的思想,单调栈维护答案,即不被其他直线覆盖的点。
1.排序:第一关键字斜率,第二关键字截距。斜率从小到大,截距从大到小。因为相同斜率的话,截距小的会被截距大的覆盖。
2.单调栈维护:考虑何时弹出栈顶元素。假设栈内有的直线为 l i n e 1 , l i n e 2 line1,line2 line1,line2,新添加的直线为 l i n e 3 line3 line3.看 l i n e 2 line2 line2在哪种情况下被覆盖。
在这里插入图片描述
当A在B的左边时,从上向下看, l i n e 2 line2 line2被覆盖,弹出栈。
很像凸包的思想。
代码:

struct node{
    int a,b,id;
}line[maxn],stk[maxn];
int n,top;

bool cmp(node a,node b){
    if(a.a==b.a) return a.b>b.b;
    return a.a<b.a;
}
bool cmp1(node a,node b){
    return a.id<b.id;
}
double cul(node a,node b){
    return 1.0*(b.b-a.b)/(a.a-b.a);
}
int main(){
    n=read;
    for(int i=1;i<=n;i++){
        line[i].a=read,line[i].b=read,line[i].id=i;
    }
    sort(line+1,line+1+n,cmp);
    stk[++top]=line[1];
    for(int i=2;i<=n;i++){
        if(line[i].a==line[i-1].a) continue;
        while(top>1&&cul(line[i],stk[top])<=cul(stk[top],stk[top-1])) top--;
        stk[++top]=line[i];
    }
    sort(stk+1,stk+1+top,cmp1);
    for(int i=1;i<=top;i++) cout<<stk[i].id<<" ";
    return 0;
}

参考

原文地址:https://www.cnblogs.com/OvOq/p/14853010.html