水平可见直线
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;
}