bzoj1007: [HNOI2008]水平可见直线 凸包

来源:互联网 发布:javascript java 编辑:程序博客网 时间:2024/05/18 02:15

一种类似于凸包的做法。

相同斜率的直线 b小的会被b大的遮住。

不同斜率的直线最后就会构成一个像开口向上的二次函数的图像。

按照斜率排序,再一个个加到栈里面。

相同斜率的直接判断,不同斜率的直线间可以发现,设栈顶编号为(top);如果当前直线和栈中编号为(top-2)的交点横坐标在 直线(top-1)和(top-2)交点的左侧,那么当前直线就把top遮住了。

建议自己画图。

交点横坐标直接联立两个方程就可以了。

#include <iostream>#include <cstring>#include <algorithm>#include <cstdio>#include <cmath>#include <stack>using namespace std;#define esp 1e-8#define maxn 51000struct node{    double a,b;    int id;}save[maxn];int n;bool cmp(node aa,node bb){    if(fabs(aa.a-bb.a)<esp) return aa.b<bb.b;    return aa.a<bb.a;}node que[maxn];int top=0;double getp(node aa,node bb){    double tmp;    tmp=(bb.b-aa.b)/(aa.a-bb.a);    return tmp;}void deal(node aa){    while(top)    {if(fabs(que[top].a-aa.a)<esp)        {            top--;        }else if(top>1&&(getp(aa,que[top-1])<=getp(que[top],que[top-1]))) top--;else break;    }    top++;    que[top]=aa;}bool ans[maxn];void solve(){    for(int i=1;i<=n;i++)    {        deal(save[i]);    }    for(int i=1;i<=top;i++)    {        ans[que[i].id]=1;    }    for(int i=1;i<=n;i++)    {        if(ans[i])            printf("%d ",i);    }}int main(){    scanf("%d",&n);    for(int i=1;i<=n;i++)    {        scanf("%lf%lf",&save[i].a,&save[i].b);        save[i].id=i;    }    sort(save+1,save+1+n,cmp);    solve();    return 0;}


0 0
原创粉丝点击