首页 > 代码库 > [BZOJ 1007][HNOI2008]水平可见直线
[BZOJ 1007][HNOI2008]水平可见直线
Description
Input
第一行为N(0 < N < 50000),接下来的N行输入Ai,Bi
Output
从小到大输出可见直线的编号,两两中间用空格隔开,最后一个数字后面也必须有个空格
Sample Input
3
-1 0
1 0
0 0
-1 0
1 0
0 0
Sample Output
1 2
HINT
Source
这个题其实和计算几何没太大关系,需要用单调栈维护可以被看见的直线数,需注意有一个性质:若直线i没有被完全覆盖,则直线i与i-1的交点在i与i+1交点的左侧,可以自己用笔画一画来验证,为了防止被坑,先用unique将重复的直线清掉,每次清掉单调栈中被完全覆盖的直线,再放入新的直线,所有直线经过此操作后,再用ans数组记下所有可以被看见的直线的编号,sort排序得到升序的直线编号,就解出答案了
#include <stdio.h>#include <cmath>#include <algorithm>#define MAXN 50050using namespace std;double ESP=0.000000000000001; //正无穷小,判断double数是否相等int n,ans[MAXN],top=1; //ans数组保存按直线编号升序输出的答案,栈顶为top-1struct Line{ int A,B,id; //第id条直线,直线解析式为y=ax+b bool operator==(const Line &b)const { return A == b.A;} bool operator<(const Line &b)const { return A == b.A ? ( B > b.B ) : A < b.A ; } void read(int x) //输入直线 { id=x; scanf("%d%d",&A,&B); }};Line ln[MAXN],stack[MAXN]; //数组ln[]保存直线,数组stack[]保存单调栈double getLineItsX(Line l1,Line l2) //求两直线交点横坐标(由一元方程推得){ return (double)(l2.B-l1.B)/(double)(l1.A-l2.A);}void init(){ int i,j; scanf("%d",&n); for(i=1;i<=n;i++) ln[i].read(i); //读取直线}void work(){ //性质:若直线i有露出部分,则直线i与i-1的交点在i与i+1交点的左侧 int i,j; sort(&ln[1],&ln[n+1]); n=unique(&ln[1],&ln[n+1])-&ln[1]; //现在,n=不重复的直线数 for(i=1;i<=n;i++) //将直线一条一条地放入坐标系中,放入一条,就删掉被覆盖看不见的直线 { while(top>2&&getLineItsX(stack[top-1],stack[top-2])>getLineItsX(stack[top-1],ln[i])-ESP) top--; //当直线top-1被直线top和top-2覆盖掉时,直线top出栈 stack[top++]=ln[i]; //所有覆盖的直线都删光以后,加入第i条直线 } for(i=1;i<top;i++) ans[i]=stack[i].id; sort(ans+1,ans+top); //对结果按id号升序排序}void output(){ int i,j; for(i=1;i<top;i++) printf("%d ",ans[i]); printf("\n");}int main(){ init(); work(); output(); return 0;}
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。