HYSBZ/BZOJ 1007 [HNOI2008] 水平可见直线 - 计算几何

来源:互联网 发布:windows安装ipython3 编辑:程序博客网 时间:2024/06/14 04:12

题目描述

分析:
直角坐标系内,有n条直线分布,求:最大值(对于任意x,直线上能取到的max( f(x) ))构成的折线由哪些直线构成。

Solution :
把直线按照斜率从小到大排序。
从左到右:先找到中斜率最小的直线 r ,它一定属于ans的集合,找到这条直线与所有直线中横坐标最小的点(x0,y0),由x0确定下一条直线 tar(由于可能出现几条直线交 r 于同一点的情况,取这些直线中斜率最大的。)
根据这样的步骤循环找ans,直到当前直线 r 没有与其他直线的交点了为止。
O(n2)的复杂度,要加优化:
因为排了序,而且直线的斜率必须由小到大,所以,当当前直线 r 找交点的时候,可以不用考虑斜率小于这条直线的线了,由于当前找到的直线是不确定,所以只有时间上限 O(n2)

代码不好看啊,当时写的时候分了斜率大于0小于0两部分,其实没必要。

推荐一个blogby Liu Junhao

#include<cstdio>#include<algorithm>#include<cmath>using namespace std;#define MAXN 50000#define MAXM 500000#define INF 2147483646const double eps=1e-30;struct node{    int a,b,id;}s[MAXN+10],t[MAXN+10];int n,cnts,cntt,c[MAXM*2+10][2],d[MAXM*2+10][2];bool ans[MAXN+10];bool cmp(node x,node y){    if(x.a==y.a) return x.b>y.b;    return x.a<y.a;}void read(){    int x,y;    scanf("%d",&n);    for(int i=1;i<=n;i++){        scanf("%d%d",&x,&y);        if(x<0){            if(c[x+MAXM][1]){                if(c[x+MAXM][0]<y)                    c[x+MAXM][0]=y,c[x+MAXM][1]=i;            }            else                c[x+MAXM][0]=y,c[x+MAXM][1]=i;        }        else{            if(d[x+MAXM][1]){                if(d[x+MAXM][0]<y)                    d[x+MAXM][0]=y,d[x+MAXM][1]=i;            }            else                d[x+MAXM][0]=y,d[x+MAXM][1]=i;        }    }    //去掉斜率相同的直线不仅可以优化一小下下,最重要的是避免后面算交点的时候出错(出现除数为0)    for(int i=0;i<=MAXM*2;i++){        if(c[i][1]){            s[++cnts].a=i-MAXM,s[cnts].b=c[i][0];            s[cnts].id=c[i][1];        }        if(d[i][1]){            t[++cntt].a=i-MAXM,t[cntt].b=d[i][0];            t[cntt].id=d[i][1];        }    }}int main(){    read();    sort(s+1,s+cnts+1,cmp);    sort(t+1,t+cntt+1,cmp);    int r,p,q;    bool last;    if(cnts){        r=1,p=2,q=1,last=false;        ans[s[r].id]=true;    }    else{        r=1,p=1,q=2,last=true;        ans[t[r].id]=true;    }    double X=-INF;    while(true){        int tar=-1;        double x0=INF,tmp;        bool flag=false;        for(int k=p;k<=cnts;k++){            tmp=1.0*(s[k].b-s[r].b)/(s[r].a-s[k].a);            if(tmp>=X&&tmp<=x0){                if(fabs(tmp-x0)<=eps){                    if(tar!=-1&&s[k].a<s[tar].a)                        continue;                }                tar=k;                x0=tmp;            }        }        for(int k=q;k<=cntt;k++){            if(last)                tmp=1.0*(t[k].b-t[r].b)/(t[r].a-t[k].a);            else                tmp=1.0*(t[k].b-s[r].b)/(s[r].a-t[k].a);            if(tmp>=X&&tmp<=x0){                if(fabs(tmp-x0)<=eps){                    if(tar!=-1&&t[k].a<t[tar].a)                        continue;                }                tar=k;                flag=true;                x0=tmp;            }        }        if(tar==-1)            break;        if(!flag){            if(x0==X) ans[s[r].id]=false;            else X=x0;            ans[s[tar].id]=true,r=tar;            p=tar+1;        }        else{            if(x0==X){                if(!last) ans[s[r].id]=false;                else ans[t[r].id]=false;            }            else X=x0;            ans[t[tar].id]=true,r=tar;            p=cnts+1,q=tar+1;        }        last=flag;    }    for(int i=1;i<=n;i++)        if(ans[i])            printf("%d ",i);}
0 0
原创粉丝点击