可变的圆 二分?排序?

来源:互联网 发布:html时间轴 demo 源码 编辑:程序博客网 时间:2024/05/19 21:41
问题源自ACM-ICPC 北京赛区2015网络赛题目1 : The Cats' Feeding Spots
大意是这样的,给出m个点,选其中一个点作为圆心画一个圆能把n个点包含在里面(边界不能有点),求最小的半径,找不到这样的半径输出-1。
自己最开始的思路是这样的,以其中一个点作为圆心,然后用伪二分法查找半径(初始化 low=1,high=1416。1000*2^0.5=1414.213),因为毕竟不是高效正统的二分,所以暂时叫它伪二分吧。
#include <iostream>#include <cstdio>#include <cstring>#include <cmath>using namespace std;const int maxn=105;int n,m;struct node{    double x,y;}p[maxn];int r[maxn];double dis(node a,node b){    return fabs(sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)));}int in(int dex,int d){    int res=0;    double dd=d*1.0;    for(int i=0;i<m;i++){         if(dd-dis(p[dex],p[i])>1e-6)                res++;    }    return res;}int mf(int dex){    int low=1,high=1416,mid;  //1000*2^0.5=1415    while(low<=high){        mid=(low+high)/2;        int sum=in(dex,mid);        if(sum>=n) high=mid-1;        else return mid;    }    return mid;}int main(){    //freopen("cin.txt","r",stdin);    int t;    cin>>t;    while(t--){        scanf("%d%d",&m,&n);        memset(r,-1,sizeof(r));        for(int i=0;i<m;i++){            scanf("%lf%lf",&p[i].x,&p[i].y);        }        for(int i=0;i<m;i++){            int w=mf(i);            if(in(i,w)==n) r[i]=w;            while(r[i]==-1&&w<=1415){                w++;                if(in(i,w)==n) break;            }            if(r[i]==-1)r[i]=w;            for(int j=0;j<m;j++){                if(fabs(dis(p[i],p[j])-r[i])<1e-6) {                    r[i]=-1;                    break;                }            }        }        int ans=2000;        for(int i=0;i<m;i++){            if(r[i]<=1415&&r[i]>=1)ans=min(ans,r[i]);        }        if(ans>1415)puts("-1");        else printf("%d\n",ans);    }    return 0;}

是的,感觉有点乱,而且时间用了800ms。我看了一份更加优秀的代码,它的思路大致是这样,找圆心的部分也是普通的循环遍历,查找最小半径:对于每一个圆心都计算出它和别的点的距离,然后使用快速排序:
for(int j=0;j<m;j++){
    dis[j]=sqrt((data[j].x-data[i].x)*(data[j].x-data[i].x)+(data[j].y-data[i].y)*(data[j].y-data[i].y));
}
sort(dis,dis+m);
包含n个点的半径应该就是(int)dis[n-1]+1,用ans保存最小的值最后输出结果(不贴代码了,没有别人的许可)。我的做法有许多的修正工作,所以计算次数是100*max(log2(100),100)*100,后者的计算是100*100*(log2(100),优劣很快就能区分开。总之,提升水平。。。
0 0
原创粉丝点击