【凸壳】【HNOI 2008】【bzoj 1007】水平可见直线

1007: [HNOI2008]水平可见直线

Time Limit: 1 Sec  Memory Limit: 162 MB
Submit: 4567  Solved: 1686

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

题解:

第一眼我觉得这是一个半平面交,然而仔细看题后发现其实没那么复杂,只需要维护一个下凸壳就好了。

Code:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 50100

struct E{
    int xu,a,b;
}e[N],ee[N];
int n,top=0,num=0,z[N];

int in(){
    int x=0; char ch=getchar(); bool f=true;
    while (ch<‘0‘ || ch>‘9‘){
        if (ch==‘-‘) f=false;
        ch=getchar();
    }
    while (ch>=‘0‘ && ch<=‘9‘) x=x*10+ch-‘0‘,ch=getchar();
    if (!f) x=-x;
    return x;
}

bool cmp1(E x,E y){
    return x.a>y.a;
}
bool cmp2(int x,int y){
    return ee[x].xu<ee[y].xu;
}

double jiao(E x,E y){
    return (double)((double)(y.b-x.b)/(double)(x.a-y.a));
}

int main(){
    n=in(); z[++top]=1;
    for (int i=1; i<=n; i++)
        e[i].xu=i,e[i].a=in(),e[i].b=in();

    sort(e+1,e+n+1,cmp1);
    for (int i=1; i<=n; i++){
        if (e[i].a!=ee[i-1].a) ee[++num]=e[i];
        else if (e[i].b>ee[num].b) ee[num]=e[i];
    }
    for (int i=2; i<=num; i++){
        while (top>=2){
            double x1=jiao(ee[z[top-1]],ee[i]);
            double x2=jiao(ee[z[top]],ee[i]);
            if (x1<=x2+1e-6) top--;
            else break;
        }
        z[++top]=i;
    }

    sort(z+1,z+top+1,cmp2);
    for (int i=1; i<=top; i++) printf("%d ",ee[z[i]].xu);
    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-16 23:18:28

【凸壳】【HNOI 2008】【bzoj 1007】水平可见直线的相关文章

BZOJ 1007 水平可见直线 | 计算几何

BZOJ 1007 水平可见直线 题面 平面直角坐标系上有一些直线,请求出在纵坐标无限大处能看到哪些直线. 题解 将所有直线按照斜率排序(平行的直线只保留最高的直线),维护一个栈,当当前直线与栈顶直线的交点在栈顶两条直线的交点的左边,则弹出栈顶元素.可以画图证明这是正确的(因为我们要维护一个下凸的图形). #include <cmath> #include <cstdio> #include <cstring> #include <algorithm> us

bzoj 1007 水平可见直线 半平面交稀里糊涂的过了...

题意:按y=Ax+B的形式给出n(<=50000)条直线,求从y值为无穷大的地方向下看能看到的直线编号 一看到题目就想到半平面交,以每条直线的上方为一个半平面,求半平面的交,交集中存在的直线就是能看到的直线 但是写出来之后发现样例都过不了... 对于样例,如果允许半平面在边界处重叠那么答案是1,2,3,如果不允许只有1.. 然后抱着试一试的心理交上去了,结果竟然直接AC了.. 后来看题解只需要考虑交点x坐标.. bzoj 1007 水平可见直线 半平面交稀里糊涂的过了...,布布扣,bubuko

bzoj 1007 水平可见直线

bzoj 1007 水平可见直线 这里的半平面都是 \(y\geq kx+b\) 类型的,将直线 \(l:y=kx+b\) 对应到点 \((k,-b)\) ,转化成凸包求解即可. 如果有两种类型,需分类后分别求上下凸包,最后去重,合并. #include<bits/stdc++.h> using namespace std; #define ll long long #define mp make_pair #define pii pair<int,int> inline int

【BZOJ】1007 水平可见直线

[分析] 维护一个下凸包. 首先依照斜率来从小到大排序. 考虑斜率同样的,肯定仅仅能选截距大的,把截距小的给筛掉. 然后用栈来维护下凸包.先压入前两条直线. 然后对于每一条直线i,设栈中上一条直线p=stk[stk[0]]和上上条直线q=stk[stk[0]-1]. 找到i与p的交点m.p与q的交点n. 画三条直线,把n点看成固定的,因为斜率从小到大,要使得上一条直线p看不到.那么m一定在n的左边,即m.x<=n.x. 假设看不到,就退栈,直到在右边. 最后输出,注意可能会存在n=1的情况.这个

1007: [HNOI2008]水平可见直线[维护下凸壳]

1007: [HNOI2008]水平可见直线 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 7184  Solved: 2741[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是被覆盖的.给

【BZOJ】【1007】【HNOI2008】水平可见直线

计算几何初步 其实是维护一个类似下凸壳的东西?画图后发现其实斜率是单调递增的,交点的横坐标也是单调递增的,所以排序一下搞个单调栈来做就可以了…… 看了hzwer的做法…… 1 /************************************************************** 2 Problem: 1007 3 User: Tunix 4 Language: C++ 5 Result: Accepted 6 Time:252 ms 7 Memory:2812 kb 8

AC日记——[HNOI2008]水平可见直线 bzoj 1007

1007 思路: 维护一个下凸壳: 用单调栈来维护这玩意儿: 先将斜率排序: 然后判断栈顶元素和当前元素的交点x是否小于栈顶元素和栈顶上一个元素的交点x: 注意: 人神共愤的精度问题和输出空格问题: 来,上代码: #include <cmath> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #d

BZOJ 1010 玩具装箱toy(四边形不等式优化DP)(HNOI 2008)

Description P教授要去看奥运,但是他舍不下他的玩具,于是他决定把所有的玩具运到北京.他使用自己的压缩器进行压缩,其可以将任意物品变成一堆,再放到一种特殊的一维容器中.P教授有编号为1...N的N件玩具,第i件玩具经过压缩后变成一维长度为Ci.为了方便整理,P教授要求在一个一维容器中的玩具编号是连续的.同时如果一个一维容器中有多个玩具,那么两件玩具之间要加入一个单位长度的填充物,形式地说如果将第i件玩具到第j个玩具放到一个容器中,那么容器的长度将为 x=j-i+Sigma(Ck) i<

BZOJ 1007: [HNOI2008]水平可见直线( 计算几何 )

按A从小到大排序然后用栈解决. -------------------------------------------------------------------- #include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 50009; struct L { int A, B, id; inline void Read(int p) { scanf("%d%d"