bzoj1007 [HNOI2008]水平可见直线 - 几何 - hzwer.com

时间:2023-03-09 05:36:51
bzoj1007 [HNOI2008]水平可见直线 - 几何 - hzwer.com

Description

bzoj1007 [HNOI2008]水平可见直线 - 几何 - hzwer.com

Input

第一行为N(0 < N < 50000),接下来的N行输入Ai,Bi

Output

从小到大输出可见直线的编号,两两中间用空格隔开,最后一个数字后面也必须有个空格

Sample Input

3
-1 0
1 0
0 0

Sample Output

1 2

题解

算法比较直观,先按斜率排序,再将最小的两条线入栈,然后依次处理每条线,如果其与栈顶元素的交点在上一个点的左边,则将栈顶元素出栈 ;这样为什么对呢?因为对如任意一个开口向上的半凸包,从左到右依次观察每条边和每个顶点,发现其斜率不断增大,顶点的横坐标也不断增大。

 #include<cstdio>
#include<algorithm>
#include<cmath>
#include<iostream>
#include<cstring>
#define eps 0.0000001
using namespace std; int top,n;
bool boo[];
struct Node
{
double x,y;
int num;
}a[],stack[]; double rope(Node x,Node y)
{
return (y.y-x.y)/(x.x-y.x);
}
bool cmp(Node x,Node y)
{
if (fabs(x.x-y.x)<eps) return x.y<y.y;
else return x.x<y.x;
}
void solve()
{
for (int i=;i<=n;i++)
{
while(top)
{
if (fabs(stack[top].x-a[i].x)<=eps) top--;//后者b大
else if (top>&&rope(a[i],stack[top-])<=rope(stack[top],stack[top-])) top--;
else break;
}
stack[++top]=a[i];
}
for (int i=;i<=top;i++)
boo[stack[i].num]=;
for (int i=;i<=n;i++)
if (boo[i]) printf("%d ",i);
}
int main()
{
scanf("%d",&n);
for (int i=;i<=n;i++)
{
scanf("%lf%lf",&a[i].x,&a[i].y);
a[i].num=i;
}
sort(a+,a+n+,cmp);
solve();
}