大意 给出一堆点,任选三点连成三角形,以三个顶点为圆心做半径相同的圆,圆之间不能相交,但可以相切或相离
求圆的最大半径
最大圆的半径,就是三角形最小的那条边的一半。否则超过一半的话,从另一个顶点再做一个圆,一定会相交
题意很简单,关键是优化时间效率。
我们先用 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; }