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

题目描述

分析:
直角坐标系内,有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 2147483646
const 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);
}
posted @ 2016-02-02 14:44  KatarinaYuan  阅读(143)  评论(0编辑  收藏  举报