poj 2932 Coneology(平面扫描)

题意:给定n个不相交的圆,求哪些圆是最外层的(不包含与其他任何圆中)


用平面扫描的思想。

假设有三个圆a,b,c,若a包含b,b包含c,则a必包含c,所以检测一个圆如果被包含,只要检测他是否被最外面的那些圆包含即可。这样用一个set来维护最外面的那些圆的集合。

还有一个性质就是并不需要检测所有的最外层的圆,只需检测在set中y轴方向上距离最近的两个圆是否包含被检测的圆即可,这个画一下图就知道了。


所以流程就是先把所有圆的最左端,最右端排序,然后从左往右扫:

如果扫到左端的点,那么就判断一下当前set中y轴距离最近的两个圆是否包含它,如果不包含,那它也是最外层的点,也把他加到set里。并把这个圆加到答案中。

如果扫到右端的点,那么如果这个圆在set里就把它删掉。


因为判断inside时脑残的用了int型wa了一次。。


代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <set>
#include <map>
#include <algorithm>
#include <vector>
#define maxn 100010
using namespace std;

struct node{
    int id;
    double pos;
}N[100010];

double r[maxn],x[maxn],y[maxn];

set <pair<double ,int > >out;
vector <int >res;
bool cmp(node a,node b){
    return a.pos<b.pos;
}
bool inside(int a,int b){
    double tx=x[a]-x[b];
    double ty=y[a]-y[b];
    if(tx*tx+ty*ty<=r[b]*r[b])
        return 1;
    return 0;
}

int main(){
    int n;
    while(~scanf("%d",&n)){
        out.clear();
        res.clear();
        for(int i=1;i<=n;i++){
            scanf("%lf%lf%lf",&r[i],&x[i],&y[i]);
            N[i].pos=x[i]-r[i];
            N[i].id=i;
            N[i+n].pos=x[i]+r[i];
            N[i+n].id=i+n;
        }
        sort(N+1,N+2*n+1,cmp);
        for(int i=1;i<=2*n;i++){
            int k=N[i].id;
            if(k>n) k-=n;
            if(N[i].id<=n){
                set <pair<double,int > > ::iterator p;
                p=out.lower_bound(make_pair(y[k],k));
                if(p!=out.end()&&inside(k,p->second)) continue;
                if(p!=out.begin()&&inside(k,(--p)->second)) continue;
                out.insert(make_pair(y[k],k));
                res.push_back(k);
            }
            else{
                out.erase(make_pair(y[k],k));
            }
        }
        sort(res.begin(),res.end());
        printf("%d\n",res.size());
        for(int i=0;i<res.size();i++){
            printf("%d",res[i]);
            if(i==res.size()-1) printf("\n");
            else printf(" ");
        }

    }
    return 0;
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值