您的位置:首页 > 其它

bzoj 1007: [HNOI2008]水平可见直线

2016-03-04 19:15 417 查看
Time Limit: 1 Sec  Memory Limit: 162 MB
Submit: 5308  Solved: 1990
[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 题解:

  先按斜率排序,再将最小的一条线入栈,然后依次处理2~N条线,如果第i条直线与stack[top]直线的交点在stack[top]和stack[top-1]直线度左边,则top--,具体可以画几条线模拟一下。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
using namespace std;
const double eps=1e-6;
const int maxn=50010;
struct bian{
double k,b;
int id;
}str[maxn];
int cmp(const bian &x1,const bian &x2){
return x1.k<x2.k||(fabs(x1.k-x2.k)<eps&&x1.b<x2.b);
}
inline double crossx(int x1,int x2){
return (str[x2].b-str[x1].b)/(str[x1].k-str[x2].k);
}
int stack[maxn],top;
int N,ans[maxn];
int main(){
scanf("%d",&N);
for(int i=1;i<=N;i++){
scanf("%lf%lf",&str[i].k,&str[i].b);
str[i].id=i;
}
sort(str+1,str+N+1,cmp);

stack[++top]=1;
for(int i=2;i<=N;i++){
while(top!=0){
if(fabs(str[i].k-str[stack[top]].k)<eps) top--;
if((crossx(stack[top-1],i)<=crossx(stack[top-1],stack[top]))&&top>=2)
top--;
else break;
}
stack[++top]=i;
}
for(int i=1;i<=top;i++) ans[str[stack[i]].id]=1;
for(int i=1;i<=N;i++){
if(ans[i]==1) printf("%d ",i);
}
return 0;
}

 

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: