BZOJ 1007 HNOI2008 水平可见的直线
本来以为这是一道计算几何的题
可看完题解发现。。。。。。
单调栈即可
按照a为第一关键字b为第二关键字从小到大排序
再将最小的两条线入栈,然后依次处理每条线,如果其与栈顶元素的交点在上一个点的左边,则将栈顶元素出栈
为什么是对的呢,让我们来看这个图
当我们不断往栈里加直线的时候,如果加入的直线与top-1的交点在top和top-1的交点左边,这样的话top的存在是没有任何意义的
因为斜率是单调递增的,所以我们可以用单调栈来维护
#include <bits/stdc++.h> #define eps 1e-8 using namespace std; const int MAXN=1e6+10; struct node{ double a,b; int id; }e[MAXN],stark[MAXN]; int n,top=0,vis[MAXN]={}; inline bool mycmp(node n,node m){ if(abs(n.a-m.a)<=eps) return n.b<m.b; else return n.a<m.a; } inline double cross(node xx,node yy){ return (xx.b-yy.b)/(yy.a-xx.a); } inline void insert(node xx){ while(top){ if(abs(stark[top].a-xx.a)<=eps) top--; else if(top>1&&cross(xx,stark[top-1])<=cross(stark[top-1],stark[top])) top--; else break; } stark[++top]=xx; } void init(){ cin>>n; for(int i=1;i<=n;i++){ scanf("%lf%lf",&e[i].a,&e[i].b); e[i].id=i; } sort(e+1,e+n+1,mycmp); } void solve(){ for(int i=1;i<=n;i++) insert(e[i]); for(int i=1;i<=top;i++){ vis[stark[i].id]=1; } for(int i=1;i<=n;i++){ if(vis[i]) printf("%d ",i); } } int main(){ //freopen("All.in","r",stdin); //freopen("a.out","w",stdout); init(); solve(); return 0; }
注意控制精度的问题