BZOJ 1007 HNOI 2008 水平可见直线 半平面交

75 篇文章 1 订阅
20 篇文章 0 订阅

给出一些直线,问从正上方往下看能看到哪些直线。

一道简单的计算几何题,不过我决定硬搞成半平面交233

稍微改了下,因为是维护上凸壳,所以不用处理首尾半平面相交的问题了。

y=ax+b的直线过定点(0,b),方向向量(1,a)。

right函数改成<=了。否则样例会错。

忘记排序编号怒WA一发233.

判断double没有判精度直接用==并没有WA,好神奇。之前也一直没有判精度。

#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std;
const int N = 50001;
struct Point {
    double x, y;
    Point(){}
    Point(double _x, double _y) : x(_x), y(_y) {}
    Point operator +(const Point &b) const { return Point(x + b.x, y + b.y); }
    Point operator -(const Point &b) const { return Point(x - b.x, y - b.y); }
    double operator *(const Point &b) const { return x * b.y - y * b.x; }
    Point operator *(double b) const { return Point(b * x, b * y); }
    bool operator ==(const Point &b) const { return x == b.x && y == b.y; }
} p[N];

struct Line {
    Point x, v;
    double ang; int id;
    Line(){}
    Line(const Point &_x, const Point &_v) : x(_x), v(_v) {
        ang = atan2(v.y, v.x);
    }

    bool operator <(const Line &b) const {
        if (ang == b.ang) return v * (b.x - x) < 0;
        return ang < b.ang;
    }

    bool operator ==(const Line &b) const { return ang == b.ang; }

    Point intersection(const Line &b) {
        Point u = x - b.x;
        double t = (b.v * u) / (v * b.v);
        return x + v * t;
    }
} l[N], q[N];

bool right(const Point &p, const Line &l) {
    return l.v * (p - l.x) <= 0;
}

int main() {
    static int ans[N];
    int n, i, f = 1, r = 0, m = 0;
    double a, b;
    scanf("%d", &n);
    for (i = 1; i <= n; i++) {
        scanf("%lf%lf", &a, &b);
        l[i] = Line(Point(0, b), Point(1, a));
        l[i].id = i;
    }
    sort(l + 1, l + n + 1);
    n = unique(l + 1, l + n + 1) - (l + 1);
    q[++r] = l[1]; q[++r] = l[2];
    for (i = 3; i <= n; i++) {
        while (f < r && right(q[r].intersection(q[r - 1]), l[i])) r--;
        while (f < r && right(q[f].intersection(q[f + 1]), l[i])) f++;
        q[++r] = l[i];
    }
    for (i = f; i <= r; i++)
        ans[++m] = q[i].id;
    sort(ans + 1, ans + m + 1);
    for (i = 1; i <= m; i++)
        printf("%d ", ans[i]);
    return 0;
}

1007: [HNOI2008]水平可见直线

Time Limit: 1 Sec   Memory Limit: 162 MB
Submit: 5073   Solved: 1876
[ Submit][ Status][ Discuss]

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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值