【计算几何】[HNOI2008][HYSBZ/BZOJ1007]水平可见直线

计算几何 专栏收录该内容
6 篇文章 0 订阅

题目链接

分析

如果两条直线斜率相等,显然,截距较小的那一条无论如何都不可见,删掉它们。
我们可以将剩下直线按照斜率的数值从小到大排序
假设第i条直线是可见的,然后,我们从第i+1条开始向后枚举,分别计算这条直线(设为第j条)和第i条直线交点的横坐标,记作 xi,j

xi,kxi,j(j<k)

显然,第j条直线不可见,因为
{yi>yjyk>yjxxi,jx>xi,j
通过这样,我们可以求出在第i条直线之后可见的直线是那一条。
显然,第1条直线是可见的,最后一条直线是可见的,所以,我们从第1条直线开始求出所以可见直线的编号即可。

代码

#include<cstdio>
#include<algorithm>
using namespace std;
#define MAXN 50000
int n,ln;
bool f[MAXN+10];
struct node{
    int a,b,pos;
    bool operator<(const node &x)const{
        if(x.a==a)
            return b>x.b;
        return a<x.a;
    }
    bool operator==(const node &x)const{
        return x.a==a;
    }
}a[MAXN+10],b[MAXN+10];
void Read(int &x){
    char c;
    bool f=0;
    while(c=getchar(),c!=EOF){
        if(c=='-')
            f=1;
        if(c>='0'&&c<='9'){
            x=c-'0';
            while(c=getchar(),c>='0'&&c<='9')
                x=x*10+c-'0';
            ungetc(c,stdin);
            if(f)
                x=-x;
            return;
        }
    }
}
void read(){
    Read(n);
    int i;
    for(i=1;i<=n;i++)
        Read(b[i].a),Read(b[i].b),b[i].pos=i;
    sort(b+1,b+n+1);
    ln=n;
    n=0;
    a[++n]=b[1];
    for(i=2;i<=ln;i++)
        if(!(b[i]==b[i-1]))
            a[++n]=b[i];
}
int compare(int x,int y,int a,int b){
    long long t1=1ll*x*b,t2=1ll*a*y,ty=1ll*y*b;
    t1-=t2;
    if(t1==0)
        return 0;
    if((t1>0&&ty>0)||(t1<0&&ty<0))
        return 1;
    return -1;
}
void solve(){
    int i,x,y,tx,ty,j,ti;
    for(i=1;i<n;i=ti){
        f[a[i].pos]=1;
        x=0x7fffffff,y=1;
        for(j=i+1;j<=n;j++){
            tx=a[j].b-a[i].b,ty=a[i].a-a[j].a;
            if(compare(tx,ty,x,y)<=0)
                x=tx,y=ty,ti=j;
        }
    }
    f[a[n].pos]=1;
}
void print(){
    for(int i=1;i<=ln;i++)
        if(f[i])
            printf("%d ",i);
}
int main()
{
    read();
    solve();
    print();
}
  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 打赏
    打赏
  • 扫一扫,分享海报

参与评论 您还未登录,请先 登录 后发表或查看评论
©️2022 CSDN 皮肤主题:编程工作室 设计师:CSDN官方博客 返回首页

打赏作者

outer_form

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值