1. 程式人生 > 實用技巧 >E——The cake is a lie(最小圓覆蓋)

E——The cake is a lie(最小圓覆蓋)

題目連結:https://nanti.jisuanke.com/t/A1993

恐怖如斯...這個還打算用普通幾何來做後來發現是真的傻了...

聯動題目:Circle and Points(http://poj.org/problem?id=1981)

想法是用poj的那道題目當板子,用這個半徑為r的能最多包含幾個點 然後二分答案即可。

板子部分如下:

struct point
{
    double x,y;
    void read()
    {
    scanf("%lf%lf",&x,&y);
    }
    void print()
    {
        printf(
"%lf%lf\n",x,y); } double friend dis(const point &a,const point &b) { return sqrt(sqr(a.x - b.x) + sqr(a.y - b.y)); } } p[Mn + 5]; struct alpha { double v; bool flag; bool friend operator <(const alpha &a,const alpha &b) { return a.v < b.v; } } alp[Mn
* Mn + 5]; int solve(int n,double R)//半徑為R的圓最多能覆蓋多少個點 { int MAX = 0; for(int i = 0; i < n; i++) { int t = 0; for(int j = 0; j < n; j++) { if(i == j) continue; double theta,phi,D; D = dis(p[i],p[j]); if
(D > 2.0 * R) continue; theta = atan2(p[j].y - p[i].y,p[j].x - p[i].x); if(theta < 0) theta += 2 * pi; phi = acos(D / (2.0 * R)); alp[t].v = theta - phi + 2 * pi; alp[t].flag = true; alp[t + 1].v = theta + phi + 2 * pi; alp[t + 1].flag = false; t += 2; } sort(alp,alp + t); int sum = 0; for(int j = 0; j < t; j++) { if(alp[j].flag) sum ++; else sum --; if(sum > MAX) MAX = sum; } } return MAX+1; }

全部程式碼如下:

#include<bits/stdc++.h>
#define Mn 300
#define sqr(x) ((x) * (x))
using namespace std;
const double eps = 1e-9;
const double pi = acos(-1.0);
struct point
{
    double x,y;
    void read()
    {
    scanf("%lf%lf",&x,&y);
    }
    void print()
    {
        printf("%lf%lf\n",x,y);
    }
    double friend dis(const point &a,const point &b)
    {
        return sqrt(sqr(a.x - b.x) + sqr(a.y - b.y));
    }
} p[Mn + 5];
struct alpha
{
    double v;
    bool flag;
    bool friend operator <(const alpha &a,const alpha &b)
    {
        return a.v < b.v;
    }
} alp[Mn * Mn + 5];
int solve(int n,double R)
{
    int MAX = 0;
    for(int i = 0; i < n; i++)
    {
        int t = 0;
        for(int j = 0; j < n; j++)
        {
            if(i == j)
                continue;
            double theta,phi,D;
            D = dis(p[i],p[j]);
            if(D > 2.0 * R)
                continue;
            theta = atan2(p[j].y - p[i].y,p[j].x - p[i].x);
            if(theta < 0)
                theta += 2 * pi;
            phi = acos(D / (2.0 * R));
            alp[t].v = theta - phi + 2 * pi;
            alp[t].flag = true;
            alp[t + 1].v = theta + phi + 2 * pi;
            alp[t + 1].flag = false;
            t += 2;
        }
        sort(alp,alp + t);
        int sum = 0;
        for(int j = 0; j < t; j++)
        {
            if(alp[j].flag)
                sum ++;
            else
                sum --;
            if(sum > MAX)
                MAX = sum;
        }
    }
    return MAX+1;
}
int main()
{
    int t;
    scanf("%d",&t);
    double eps=1e-5;
    while(t--)
    {
        int n,s;
        scanf("%d %d",&n,&s);
        for (int i = 0; i < n; ++i)
        {
            scanf("%lf %lf",&p[i].x,&p[i].y);
        }
        int str_r;
        scanf("%d",&str_r);
        if(n<s)
        {
            printf("The cake is a lie.\n");
        }
        else
        {
            double l=0,r=9999999;
            while(fabs(l-r)>eps)
            {
                double mid=(l+r)/2.0;
                int num=solve(n,mid);
                if (num>=s)
                {
                    r=mid;
                }
                else
                {
                    l=mid;
                }
            }
            printf("%.4f\n",l+str_r);
        }
    }
}