codeforce 333-E. Summer Earnings(bitset运算+几何)

题目:codeforce 333-E. Summer Earnings

time limit per test9 seconds

Many schoolchildren look for a job for the summer, and one day, when Gerald was still a schoolboy, he also decided to work in the summer. But as Gerald was quite an unusual schoolboy, he found quite unusual work. A certain Company agreed to pay him a certain sum of money if he draws them three identical circles on a plane. The circles must not interfere with each other (but they may touch each other). He can choose the centers of the circles only from the n options granted by the Company. He is free to choose the radius of the circles himself (all three radiuses must be equal), but please note that the larger the radius is, the more he gets paid.

Help Gerald earn as much as possible.

Input
The first line contains a single integer n — the number of centers (3 ≤ n ≤ 3000). The following n lines each contain two integers xi, yi ( - 104 ≤ xi, yi ≤ 104) — the coordinates of potential circle centers, provided by the Company.

All given points are distinct.

Output
Print a single real number — maximum possible radius of circles. The answer will be accepted if its relative or absolute error doesn’t exceed 10 - 6.

Examples
inputCopy
3
0 1
1 0
1 1
outputCopy
0.50000000000000000000
inputCopy
7
2 -3
-2 -3
3 0
-3 -1
1 -2
2 -2
-1 0
outputCopy
1.58113883008418980000
题目大意:找到三个点,使得以三个点为圆心以相同半径画一个圆,同时这三个圆不相交,可相切。问能够画的最大的圆的半径是多少?
题目思路:
一开始看着有9000ms,所以直接暴力找三个点求出三边长然后最短边,找到的所有最短边的集合中最小的就是答案。奈何数据量太大,第四组就卡掉了!!!!
后来参照题解发现可以用bitset优化来解决该题。
具体思路:先求出(n2复杂度)所有的边的集合,因为要找的边是尽可能大中的较小的,所以现将所有边从大到小排序,然后依次放入,对于每一个点i都对应着一个二进制行(bitset),它的第j位为1,表示当前i与j的边已经放入,当放入新边时,如果这条边的两个顶点都和某一点相连的边已经放入,此时找到的三点就是可满足条件的最大,而将放入的边的一半就是答案(因为这是放入的边是最小的,同时也是没放入中最大的)。

了解bitset的两个操作:a.set(b)将a的第b为变为1,a.count()返回为1的位数。

code

#include<iostream>
#include<cstdio>
#include<bitset>
#include<cmath>
#include<algorithm>
#define N 3001
#define x first
#define y second
using namespace std;
struct Node{
    int u,v;
    double val;
}a[3001*3001];
pair<int,int>p[N];
bool cmp(Node a,Node b){
    return a.val>b.val;
}
bitset<N>b[N];
int n;
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>p[i].x>>p[i].y;
    }
    int cnt=0;
    for(int i=1;i<=n;i++){
        for(int j=1;j<i;j++){
            a[++cnt]={i,j,sqrt((p[i].x-p[j].x)*(p[i].x-p[j].x)+(p[i].y-p[j].y)*(p[i].y-p[j].y))};
        }
    }
    sort(a+1,a+1+cnt,cmp);
    for(int i=1;i<=cnt;i++){
        int x=a[i].u,y=a[i].v;
        if((b[x]&b[y]).count()){
            printf("%.10lf",a[i].val/2);
            return 0;
        }
        b[x].set(y);
        b[y].set(x);
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值