20200908 专题:最小圆覆盖

总览:

随机增量法
圆的表示: ( ( 圆 心 ( x , y ) ) , 半 径 r ) ((圆心(x,y)),半径r) (((x,y)),r)
初始圆为 ( ( 0 , 0 ) , 0 ) ((0,0),0) ((0,0),0)
枚举每一个点,找到一个圆,使 p 1 − p n o w p_1-p_{now} p1pnow 在圆内
枚举每一个点 p i p_i pi,如果 p i p_i pi 不在当前圆内,假设它在圆上,将圆设为 ( ( x i , y i ) , 0 ) ((x_i,y_i),0) ((xi,yi),0)
再枚举每一个它之前的点 p j p_j pj,如果 p j p_j pj 不在当前圆内,假设它在圆上,将圆设为 ( ( p i , p j 的 中 点 ) , d i s ( p i , p j ) / 2 ) ((p_i,p_j的中点),dis(p_i,p_j)/2) ((pi,pj),dis(pi,pj)/2)
再枚举每一个 p j p_j pj 之前的点 p k p_k pk,如果 p k p_k pk 不在当前圆内,假设它在圆上,将圆设为 p i , p j , p k 的 三 点 圆 p_i,p_j,p_k的三点圆 pi,pj,pk

求三点圆:
就是找外心
找两条边的中垂线求交即可

为防被卡,开始先打乱点的顺序

T1 P1742 最小圆覆盖

思路:
板子题

代码:

#include <bits/stdc++.h>
using namespace std;
#define LL long long
typedef unsigned long long ull;
typedef unsigned int uint;
#define pb push_back
#define mp make_pair
namespace IO {
char buf_[1 << 21], *p1_ = buf_, *p2_ = buf_;
#define ch()                                                                 \
  (p1_ == p2_ &&                                                             \
           (p2_ = (p1_ = buf_) + fread(buf_, 1, 1 << 21, stdin), p1_ == p2_) \
       ? EOF                                                                 \
       : *p1_++)
inline int in() {
  int s = 0, f = 1;
  char x = getchar();
  for (; x < '0' || x > '9'; x = getchar())
    if (x == '-') f = -1;
  for (; x >= '0' && x <= '9'; x = getchar()) s = (s * 10) + (x & 15);
  return f == 1 ? s : -s;
}
char _buf[1 << 21];
int _p1 = -1;
inline void flush() {
  fwrite(_buf, 1, _p1 + 1, stdout);
  _p1 = -1;
}
inline void pc(char x) {
  if (_p1 == (1 << 21) - 1) flush();
  _buf[++_p1] = x;
}
inline void out(int x) {
  char k[30];
  int pos = 0;
  if (!x) {
    pc('0');
    return;
  }
  if (x < 0) {
    pc('-');
    x = -x;
  }
  while (x) {
    k[++pos] = (x % 10) | 48;
    x /= 10;
  }
  for (int i = pos; i; i--) pc(k[i]);
  return;
}
inline void out(string x) {
  int len = x.size();
  for (int i = 0; i < len; i++) pc(x[i]);
}
}  // namespace IO
using namespace IO;

const int A = 3e5 + 5;
const double EPS = 1e-15;
int n;
inline int cp(double u, double v) {
  if (fabs(u - v) < EPS) return 0;
  return u > v ? 1 : -1;
}
struct Point {
  double x, y;
  Point(double u = 0, double v = 0) { x = u, y = v; }
  inline friend Point operator+(Point u, Point v) {
    return Point(u.x + v.x, u.y + v.y);
  }
  inline friend Point operator-(Point u, Point v) {
    return Point(u.x - v.x, u.y - v.y);
  }
  inline friend Point operator*(Point u, double v) {
    return Point(u.x * v, u.y * v);
  }
  inline friend Point operator/(Point u, double v) {
    return Point(u.x / v, u.y / v);
  }
  inline friend double operator^(Point u, Point v) {
    return u.x * v.y - u.y * v.x;
  }
  inline friend double operator&(Point u, Point v) {
    return u.x * v.x + u.y * v.y;
  }
  inline friend bool operator==(Point u, Point v) {
    return !cp(u.x, v.x) && !cp(u.y, v.y);
  }
  inline friend bool operator!=(Point u, Point v) { return !(u == v); }
} p[A];
struct Line {
  Point x, y;
  Line(Point u = 0, Point v = 0) { x = u, y = v; }
};
struct Circle {
  Point x;
  double r;
  Circle(Point u = 0, double v = 0) { x = u, r = v; }
} mn;

inline double dis(Point u, Point v) {
  return sqrt((u.x - v.x) * (u.x - v.x) + (u.y - v.y) * (u.y - v.y));
}

inline int check(Point u, Circle v) { return cp(dis(u, v.x), v.r) != 1; }

inline Point inter(Line u, Line v) {
  double s1 = (v.x - u.x) ^ (v.y - u.x), s2 = (v.y - u.y) ^ (v.x - u.y);
  return u.x + (u.y - u.x) * s1 / (s1 + s2);
}

inline Line find(Line u) {
  Point a = (u.x + u.y) / 2;
  return Line(a, Point(a.x + (u.y - u.x).y, a.y - (u.y - u.x).x));
}

inline Circle circle(Point u, Point v, Point w) {
  Line a = find(Line(u, v)), b = find(Line(v, w));
  Point c = inter(a, b);
  return Circle(c, dis(u, c));
}

signed main() {
  srand(time(0));
  n = in();
  for (int i = 1; i <= n; i++) scanf("%lf%lf", &p[i].x, &p[i].y);
  random_shuffle(p + 1, p + 1 + n);
  mn = Circle(Point(0, 0), 0);
  for (int i = 1; i <= n; i++)
    if (!check(p[i], mn)) {
      mn = Circle(p[i], 0);
      for (int j = 1; j <= i - 1; j++)
        if (!check(p[j], mn)) {
          mn = Circle((p[i] + p[j]) / 2, dis(p[i], p[j]) / 2);
          for (int k = 1; k <= j - 1; k++) {
            if (!check(p[k], mn)) mn = circle(p[i], p[j], p[k]);
          }
        }
    }
  printf("%0.10lf\n%0.10lf %0.10lf\n", mn.r, mn.x.x, mn.x.y);
  flush();
  return 0;
}

T2 P4288 [SHOI2014]信号增幅仪

思路:
先旋转坐标轴,将椭圆转正,然后放缩,将椭圆变成圆

代码:

#include <bits/stdc++.h>
using namespace std;
#define LL long long
typedef unsigned long long ull;
typedef unsigned int uint;
#define pb push_back
#define mp make_pair
namespace IO {
char buf_[1 << 21], *p1_ = buf_, *p2_ = buf_;
#define ch()                                                                 \
  (p1_ == p2_ &&                                                             \
           (p2_ = (p1_ = buf_) + fread(buf_, 1, 1 << 21, stdin), p1_ == p2_) \
       ? EOF                                                                 \
       : *p1_++)
inline int in() {
  int s = 0, f = 1;
  char x = ch();
  for (; x < '0' || x > '9'; x = ch())
    if (x == '-') f = -1;
  for (; x >= '0' && x <= '9'; x = ch()) s = (s * 10) + (x & 15);
  return f == 1 ? s : -s;
}
char _buf[1 << 21];
int _p1 = -1;
inline void flush() {
  fwrite(_buf, 1, _p1 + 1, stdout);
  _p1 = -1;
}
inline void pc(char x) {
  if (_p1 == (1 << 21) - 1) flush();
  _buf[++_p1] = x;
}
inline void out(int x) {
  char k[30];
  int pos = 0;
  if (!x) {
    pc('0');
    return;
  }
  if (x < 0) {
    pc('-');
    x = -x;
  }
  while (x) {
    k[++pos] = (x % 10) | 48;
    x /= 10;
  }
  for (int i = pos; i; i--) pc(k[i]);
  return;
}
inline void out(string x) {
  int len = x.size();
  for (int i = 0; i < len; i++) pc(x[i]);
}
}  // namespace IO
using namespace IO;

const int A = 3e5 + 5;
const double EPS = 1e-7;
const double pi = acos(-1);
int n;
inline int cp(double u, double v) {
  if (fabs(u - v) < EPS) return 0;
  return u > v ? 1 : -1;
}
struct Point {
  double x, y;
  Point(double u = 0, double v = 0) { x = u, y = v; }
  inline friend Point operator+(Point u, Point v) {
    return Point(u.x + v.x, u.y + v.y);
  }
  inline friend Point operator-(Point u, Point v) {
    return Point(u.x - v.x, u.y - v.y);
  }
  inline friend Point operator*(Point u, double v) {
    return Point(u.x * v, u.y * v);
  }
  inline friend Point operator/(Point u, double v) {
    return Point(u.x / v, u.y / v);
  }
  inline friend double operator^(Point u, Point v) {
    return u.x * v.y - u.y * v.x;
  }
  inline friend double operator&(Point u, Point v) {
    return u.x * v.x + u.y * v.y;
  }
  inline friend bool operator==(Point u, Point v) {
    return !cp(u.x, v.x) && !cp(u.y, v.y);
  }
  inline friend bool operator!=(Point u, Point v) { return !(u == v); }
} p[A];
struct Line {
  Point x, y;
  Line(Point u = 0, Point v = 0) { x = u, y = v; }
};
struct Circle {
  Point x;
  double r;
  Circle(Point u = 0, double v = 0) { x = u, r = v; }
} mn;

inline double dis(Point u, Point v) {
  return sqrt((u.x - v.x) * (u.x - v.x) + (u.y - v.y) * (u.y - v.y));
}

inline int check(Point u, Circle v) { return cp(dis(u, v.x), v.r) != 1; }

inline Point inter(Line u, Line v) {
  double s1 = (v.x - u.x) ^ (v.y - u.x), s2 = (v.y - u.y) ^ (v.x - u.y);
  return u.x + (u.y - u.x) * s1 / (s1 + s2);
}

inline Line find(Line u) {
  Point a = (u.x + u.y) / 2;
  return Line(a, Point(a.x + (u.y - u.x).y, a.y - (u.y - u.x).x));
}

inline Circle circle(Point u, Point v, Point w) {
  Line a = find(Line(u, v)), b = find(Line(v, w));
  Point c = inter(a, b);
  return Circle(c, dis(u, c));
}

inline Point rotate(Point u, double phi) {
  return Point(cos(phi) * u.x - sin(phi) * u.y,
               sin(phi) * u.x + cos(phi) * u.y);
}

signed main() {
  srand(time(0));
  n = in();
  for (int i = 1; i <= n; i++) p[i].x = in(), p[i].y = in();
  double phi = in();
  phi = -pi * (phi / 180);
  for (int i = 1; i <= n; i++) p[i] = rotate(p[i], phi);
  int d = in();
  for (int i = 1; i <= n; i++) p[i].x = p[i].x / d;
  random_shuffle(p + 1, p + 1 + n);
  mn = Circle(Point(0, 0), 0);
  for (int i = 1; i <= n; i++)
    if (!check(p[i], mn)) {
      mn = Circle(p[i], 0);
      for (int j = 1; j <= i - 1; j++)
        if (!check(p[j], mn)) {
          mn = Circle((p[i] + p[j]) / 2, dis(p[i], p[j]) / 2);
          for (int k = 1; k <= j - 1; k++) {
            if (!check(p[k], mn)) mn = circle(p[i], p[j], p[k]);
          }
        }
    }
  printf("%0.3lf\n", mn.r);
  flush();
  return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值