您的位置:首页 > 其它

bzoj1007: [HNOI2008]水平可见直线 凸包

2014-11-28 23:36 218 查看
一种类似于凸包的做法。

相同斜率的直线 b小的会被b大的遮住。

不同斜率的直线最后就会构成一个像开口向上的二次函数的图像。

按照斜率排序,再一个个加到栈里面。

相同斜率的直接判断,不同斜率的直线间可以发现,设栈顶编号为(top);如果当前直线和栈中编号为(top-2)的交点横坐标在 直线(top-1)和(top-2)交点的左侧,那么当前直线就把top遮住了。

建议自己画图。

交点横坐标直接联立两个方程就可以了。

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <stack>
using namespace std;
#define esp 1e-8
#define maxn 51000
struct node
{
double a,b;
int id;
}save[maxn];
int n;
bool cmp(node aa,node bb)
{
if(fabs(aa.a-bb.a)<esp) return aa.b<bb.b;
return aa.a<bb.a;
}
node que[maxn];
int top=0;
double getp(node aa,node bb)
{
double tmp;
tmp=(bb.b-aa.b)/(aa.a-bb.a);
return tmp;
}
void deal(node aa)
{
while(top)
{
if(fabs(que[top].a-aa.a)<esp)
{
top--;
}
else if(top>1&&(getp(aa,que[top-1])<=getp(que[top],que[top-1]))) top--;
else break;
}
top++;
que[top]=aa;
}
bool ans[maxn];
void solve()
{
for(int i=1;i<=n;i++)
{
deal(save[i]);
}
for(int i=1;i<=top;i++)
{
ans[que[i].id]=1;
}
for(int i=1;i<=n;i++)
{
if(ans[i])
printf("%d ",i);
}
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%lf%lf",&save[i].a,&save[i].b);
save[i].id=i;
}
sort(save+1,save+1+n,cmp);
solve();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: