Codeforces 333E Summer Earnings【bitset模板题】

大意  给出一堆点,任选三点连成三角形,以三个顶点为圆心做半径相同的圆,圆之间不能相交,但可以相切或相离

        求圆的最大半径

 

最大圆的半径,就是三角形最小的那条边的一半。否则超过一半的话,从另一个顶点再做一个圆,一定会相交

题意很简单,关键是优化时间效率。

我们先用 n^2 的时间计算出每条边的距离,把他们从大到小排序(便于找出最长边)并枚举,设两端点为 u 和 v

我们用一个 bitset 数组 a 存储枚举到当前状态下 u v 所能到达的点。通过 & 可以判断当前的 u v是否已经可以到达同一个点

如果可以, 这条边就是三角形中的最短边

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <bitset>
#define ll long long
using namespace std;
const int maxn = 5e6;
bitset<3005> a[3005];
struct edge{ 
    ll len, s, t;
}e[maxn]; //存储边
struct node{
    ll x, y;
}p[3005];//存储顶点
bool cmp(edge a, edge b){
    return a.len > b.len;
}//从大到小排序
ll getlen(int i, int j){
    return (p[i].x-p[j].x)*(p[i].x-p[j].x)+(p[i].y-p[j].y)*(p[i].y-p[j].y);
}//获得边长的平方
int main() {
    int n; scanf("%d", &n);
    for(int i=1; i<=n; i++) scanf("%lld%lld", &p[i].x, &p[i].y);
    int cnt = 0;
    for(int i=1; i<=n; i++){
        for(int j=1; j<=n; j++){
            e[++cnt].len = getlen(i, j);
            e[cnt].s = i;
            e[cnt].t = j;
        }
    }
    sort(e+1, e+1+cnt, cmp);//排序边长
    ll maxx = 0;
    for(int i=1; i<=cnt; i++){//遍历边
        int u = e[i].s, v = e[i].t;
        bitset<3005> tmp = a[u]&a[v]; //tmp是u,v都可以到达的点
        if(tmp.any()){ //如果u,v此时能到达同一个点,由于我们是从大到小排序,这条边就是我们需要的最长的最短边
            maxx = e[i].len;
            break;//就可以直接得到答案break掉了
        }
        a[u].set(v);//否则记录u能到达v,v能到达u
        a[v].set(u);
    }
    double ans = sqrt(maxx)/2;
    printf("%.10lf", ans);
    return 0;
}

 

posted @ 2020-04-11 20:23  poozhai  阅读(159)  评论(0编辑  收藏  举报