BZOJ 1007 [HNOI2008]水平可见直线

没想到自己竟然会做计算几何。。不过这确实是一道水题。

观察发现最后的可见直线是一个凸包。把所有直线按斜率排序,开一个栈存直线,计算当前直线和前一条的交点,若x坐标小于前一个交点则弹栈。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#define INF 1e18
typedef long long LL;
const int maxn=1e5+299;
using namespace std;
int n,r,sta[maxn],ans[maxn];
double k,b;
struct edge{
    int id;
    double k,b,x,y;
    friend bool operator < (const edge&A,const edge&B) {
        return (A.k<B.k)||(A.k==B.k&&A.b>B.b);
    }
    edge(){}
    edge(int id,double k,double b):id(id),k(k),b(b){}
}e[maxn];
double cal(int i,int j) {
    return (e[i].b-e[j].b)/(e[j].k-e[i].k);
}
void init() {
    scanf("%d",&n);
    for(int i=1;i<=n;i++) {
        scanf("%lf%lf",&k,&b);
        e[i]=edge(i,k,b);
    }
}
void work() {
    sort(e+1,e+n+1);
    for(int i=1;i<=n;i++) {
        if(r&&e[i].k==e[sta[r]].k) continue;
        double xx=cal(sta[r],i);
        while(r) {
            if(xx>e[sta[r]].x) break;
            r--;
            xx=cal(sta[r],i);
        }
        sta[++r]=i;
        if(r!=1)  e[i].x=xx;
        else e[i].x=-INF;
    } 
    for(int i=1;i<=r;i++) ans[e[sta[i]].id]=1;
    for(int i=1;i<=n;i++) if(ans[i]) printf("%d ",i);
}
int main()
{
    init();
    work();
    return 0;
}
View Code

 

posted @ 2017-09-22 18:43  啊宸  阅读(166)  评论(0编辑  收藏  举报