BNUOJ 53081 线段树区间合并
The 2018 ACM-ICPC Asia Qingdao Regional Contest, Online B Red Black Tree (LCA)

ACM-ICPC 2018 沈阳赛区网络预赛 E. The cake is a lie(最小圆覆盖至少m个点)

zjhl2 posted @ 2018年9月12日 21:27 in with tags 计算几何 , 452 阅读

题目链接:

https://nanti.jisuanke.com/t/31446

 

题意:

给你n个半径都为r的圆(n<=300),用一个大圆至少覆盖s个圆,问大圆的最小半径。

 

思路:

首先发现问题转化为求覆盖n个点中至少s个点的最小圆的半径,再加r就是答案。

于是就可以二分这个大圆的半径R,以每个点为圆心画圆,看是否有区域被覆盖了s次。

具体思路看知乎:https://www.zhihu.com/question/266750532/answer/312982493

 

#include<bits/stdc++.h>
using namespace std;
const double eps=1e-8,pi=acos(-1);
int sgn(double x){
    if (x<-eps) return -1;
    if (x>eps) return 1;
    return 0;
}
double fm(double x){
    while(x>pi) x-=2*pi;
    while(x<-pi) x+=2*pi;
    return x;
}
struct P{
    double x,y;
    double len(){
        return sqrt(x*x+y*y);
    }
    bool operator<(const P &t)const{
        return x<t.x||x==t.x&&y>t.y;
    }
    bool operator==(const P &t)const{
        return x==t.x&&y==t.y;
    }
    P operator-(const P &t)const{
        return {x-t.x,y-t.y};
    }
    double slope(){
        return atan2(y,x);
    }
};
double dis(const P &a,const P &b){
    return (a-b).len();
}

const int N=305;
P a[N],stk[N*2];
bool check(int n,int S,double R){
    int ans=0;
    for (int i=1;i<=n;i++){
        int cnt=0;
        int top=0;
        for (int j=1;j<=n;j++){
            if (a[i]==a[j]){
                cnt++;
                continue;
            }
            if (sgn(dis(a[i],a[j])-2*R)>=0) continue;
            double alpha=acos(dis(a[i],a[j])/2/R);
            double k=(a[j]-a[i]).slope();
            double st=fm(k-alpha),ed=fm(k+alpha);
            if (st<ed){
                stk[++top]={st,1};
                stk[++top]={ed,-1};
            }
            else{
                cnt++;
                stk[++top]={ed,-1};
                stk[++top]={st,1};
            }
        }
        sort(stk+1,stk+top+1);
        if (cnt>=S) return 1;
        for (int i=1;i<=top;i++){
            if (stk[i].y<0) cnt--;
            else cnt++;
            if (cnt>=S) return 1;
        }
    }
    return 0;
}
double solve(int n,int S){
    double l=0,r=0; 
    for (int i=1;i<=n;i++)
        for (int j=1;j<=n;j++) r=max(r,dis(a[i],a[j]));
    while(r-l>1e-6){
        double mid=(l+r)/2;
        if (!check(n,S,mid)) l=mid;
        else r=mid;
    }
    return l;
}
int main(){
    int t; scanf("%d",&t);
    while(t--){
        int n,S; scanf("%d%d",&n,&S);
        for (int i=1;i<=n;i++) scanf("%lf%lf",&a[i].x,&a[i].y);
        double R; scanf("%lf",&R);
        if (S>n) printf("The cake is a lie.\n");
        else printf("%.4f\n",solve(n,S)+R);
    }
}

 


登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter