题意:在一个平面内给出n(3 <= n <= 3000)个点的坐标,任选其中三个为圆心作半径相同的圆,要求这三个圆不能相交但可以相切,求能画出的圆中的最大半径
暴力做法:三重循环枚举三个点,每次更新答案,直至找到最长的最短边 但这样三重循环明显超时(虽然程序运行时间设定为了9s)
但其实第三次循环很没有必要 因为我只需要知道最短边 我并不需要知道这个三角形长什么样子 我只需要知道这个最长的最短边可以为成三角形就结束了
思路:将所有边从大到小存起来 从大的边开始枚举 当枚举到有三条边围成三角形时 此时枚举的边就是我们要找的最大的最短边
我现在的思路:给点编号,再将起点,终点,距离存起来,使用维护size的并查集,从最大边开始枚举,每枚举一条边,就将这条边上的两点merge,直到有一个size == 3,那么此时枚举到的边就是最长的最短边,他的一半就是最大的半径 但这样不对 因为size == 3是建立在成环的基础上 完全可以不成环也使size == 3(三个点连成一条线) 先继续听她讲课吧
bitset横空出世 它相当于一个01字符串 但是又可以像数组一样引用 类似string s[N],我既可以引用s[i],又可以引用s[i][j] 此处运用 位运算+bitset 其实我就是要找两点连向了一个公共点 那么设前一个点为i,后一个点为j
如果它们有公共点 那么(bitset[i] & bitset[j]) != 0 因为没有公共点则没有公共位上的数字同为1 那么进行与(&)运算就为0
如果没有公共点 那么bitset[i][j] = 1, bitset[j][i] = 1
真的非常巧妙原来bitset还可以这样使用 真是长见识了
注意注意注意 !!! 位运算一定要打括号 刚刚没打括号报错了 一定要记住

#include <bits/stdc++.h>
using namespace std;
const int N = 3010;
int x[N], y[N];
bitset<N> vis[N];
int m = 0;

struct Node {
  int len;
  int x, y;
}c[N * N];

int dist(int a, int b) {
  return (x[a] - x[b]) * (x[a] - x[b]) + (y[a] - y[b]) * (y[a] - y[b]);
}

int main () {
  int n;scanf("%d", &n);
  for (int i = 1;i <= n; ++ i) scanf("%d%d", &x[i], &y[i]);
  for (int i = 1;i <= n; ++ i) {
    for (int j = i + 1;j <= n; ++ j) {
      c[++ m].len = dist(i, j);
      c[m].x = i, c[m].y = j; 
    }
  } 
  sort(c + 1, c + m + 1, [](const Node &u, const Node &v) {
    return u.len > v.len;
  });
  for (int i = 1;i <= m; ++ i) {
    //位运算一定要打括号 切记切记!!!
    if ((vis[c[i].x] & vis[c[i].y]) != 0) {
      printf("%.12lf", sqrt(c[i].len) / 2);
      break;
    }
    else vis[c[i].x][c[i].y] = 1, vis[c[i].y][c[i].x] = 1;
  }
}