[BZOJ1007][HNOI2008]水平可见直线-半平面交

水平可见直线

Description

  在xoy直角坐标平面上有n条直线L1,L2,…Ln,若在y值为正无穷大处往下看,能见到Li的某个子线段,则称Li为可见的,否则Li为被覆盖的.
  例如,对于直线:L1:y=x; L2:y=-x; L3:y=0,则L1和L2是可见的,L3是被覆盖的.

  给出n条直线,表示成y=Ax+B的形式(|A|,|B|<=500000),且n条直线两两不重合.求出所有可见的直线.

Input

  第一行为N(0 < N < 50000),接下来的N行输入Ai,Bi

Output

  从小到大输出可见直线的编号,两两中间用空格隔开,最后一个数字后面也必须有个空格

Sample Input

3
-1 0
1 0
0 0

Sample Output

1 2


来复习一下半平面交……
这是为填一个史前巨坑所做准备……


思路:
半平面交裸题.jpg

这题中半平面交的做法:
1.对所有直线按斜率排序,斜率相同则只保留b较小的那一个
2.依次插入直线,若当前直线与栈顶直线的交点在栈顶直线与栈顶-1处的直线交点的左边,那么弹掉栈顶,继续重复直到栈顶只有一根直线或不满足弹栈条件时,将当前直线加入栈顶。
3.剩下的直线便是半平面交
4.没有四了做完了

#include<bits/stdc++.h>

using namespace std;

typedef double db;
typedef pair<db,db> pr;
#define x first
#define y second
const int N=50509;
const db eps=1e-7;

struct line
{
    db k,b;int id;
    bool operator < (line o)const
    {
        if(fabs(k-o.k)<eps)
            return b<o.b;
        return k<o.k;
    }
}l[N];

int n,stk[N],top;
bool ans[N];

pr point(line a,line b)
{
    db x=(a.b-b.b)/(b.k-a.k);
    return pr(x,a.k*x+a.b);
}

inline void push(int id)
{
    while(top>=2)
    {
        pr pc=point(l[stk[top]],l[id]);
        pr pt=point(l[stk[top]],l[stk[top-1]]);
        if(pc.x-pt.x<eps)top--;
        else break;
    }
    stk[++top]=id;
}

int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%lf%lf",&l[i].k,&l[i].b),l[i].id=i;
    sort(l+1,l+n+1);

    for(int i=1;i<=n;i++)
        if(i==n || fabs(l[i].k-l[i+1].k)>eps)
            push(i);
    for(int i=1;i<=top;i++)
        ans[l[stk[i]].id]=1;
    for(int i=1;i<=n;i++)
        if(ans[i])
            printf("%d ",i);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值