CF333E Summer Earnings

题目

https://codeforces.com/problemset/problem/333/E

题解

知识点:枚举,图论,位运算。

题目要求从给定的坐标中的选取三个点为圆心,画出 3 个不相交且半径相等的圆,并求圆半径可能的最大值。

显然,题目可以转化为,任选三个点,找到构成三角形最短边长的 1/2 中的最大值,直接枚举三个点的复杂度是 O(n3) 是不行的。

考虑不从找点角度构成三角形,因为没有操作空间,而先预处理出边端点序号和边长信息记录到边结构体中,复杂度是 O(n2) ,从找边角度去构成三角形。但单纯找边也是 O(n3) ,需要优化。

既然要找到最长边,可以考虑先把边长从大到小排序,从长边到短边开始找,这样找到第一条能和已经遍历过的较长边构成三角的边就是最大的边。

每次处理一个边,将会记录边对应两个端点的互连的信息,表示这条边已枚举,这里可以给点结构体增设一个 bitset 变量 bsbs[i] 表示为这个点是否已与 i 号点相连,用 bitset 类型而不用 bool 数组主要考虑到空间问题和位运算便捷的操作。

最后找到一条边,能和已经枚举的较长边互连成三角形,这条边边长的 1/2 即是答案。若要构成三角形,则这条边两个端点的有一个相同的连接点,而通过两个端点各自 bs 进行 & 运算的结果可以得到两端点是否连接了同一个点。

时间复杂度 O(n2logn)

空间复杂度 O(n2)

代码

#include <bits/stdc++.h>
using namespace std;
struct dot{
int x,y;
bitset<3007> bs;
}d[3007];
struct len_dot{
int len,a,b;
}ld[3000*3000+7];
int cnt = 0;
int dist2(int a,int b){
return (d[a].x - d[b].x)*(d[a].x - d[b].x) + (d[a].y - d[b].y)*(d[a].y - d[b].y);
}
bool cmp(len_dot a,len_dot b){
return a.len>b.len;
}
int main(){
int n;
cin>>n;
for(int i = 0;i<n;i++){
cin>>d[i].x>>d[i].y;
}
for(int i = 0;i<n;i++){
for(int j = i+1;j<n;j++){
ld[cnt].len = dist2(i,j);
ld[cnt].a = i;
ld[cnt].b = j;
cnt++;
}
}
sort(ld,ld+cnt,cmp);
double ans;
for(int i = 0;i<cnt;i++){
if((d[ld[i].a].bs & d[ld[i].b].bs).any()){
ans = sqrt(ld[i].len)/2;
break;
}
d[ld[i].a].bs[ld[i].b] = 1;
d[ld[i].b].bs[ld[i].a] = 1;
}
cout<<fixed<<ans<<'\n';
return 0;
}
posted @   空白菌  阅读(37)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
点击右上角即可分享
微信分享提示