20200908 专题:最近点对

总览:

随机化可过大部分题……
随机旋转坐标轴,按 x x x 排序,对每个点和后面几个点求距离,取最小

KDtree可做

分治是正常方法
将点按 x x x 排序,以中点为分治中心,递归处理
当合并时,发现对于 [ m i d x − a n s , m i d x + a n s ] [mid_x-ans,mid_x+ans] [midxans,midx+ans] 外的点,一定不优,可以排除
在这里插入图片描述
将中间的点按 y y y 排序,同理, [ m i d y − a n s , m i d y + a n s ] [mid_y-ans,mid_y+ans] [midyans,midy+ans] 外的点不优,排除
对剩下的所有点两两求距离

T1 P1429 平面最近点对(加强版)

思路:
板子

代码:

#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 = 2e5 + 5;
const double INF = 1e15;
const double EPS = 1e-9;
const double pi = acos(-1);
inline int cp(double u, double v) {
  if (fabs(u - v) < EPS) return 0;
  return u > v ? 1 : -1;
}
int n;
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); }
  inline friend bool operator<(Point u, Point v) {
    if (cp(u.x, v.x)) return u.x < v.x;
    return u.y < v.y;
  }
} p[A];
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 Point rotate(Point u, double phi) {
  return Point(u.x * cos(phi) - u.y * sin(phi),
               u.x * sin(phi) + u.y * cos((phi)));
}

double ans;

inline void work(double phi) {
  for (int i = 1; i <= n; i++) p[i] = rotate(p[i], phi);
  sort(p + 1, p + 1 + n);
  for (int i = 1; i < n; i++)
    for (int j = 1; i + j <= n && j <= 5; j++)
      ans = min(ans, dis(p[i], p[i + j]));
  return;
}

signed main() {
  srand(time(0));
  n = in();
  ans = INF;
  for (int i = 1; i <= n; i++) scanf("%lf%lf", &p[i].x, &p[i].y);
  for (int i = 1; i <= 20; i++) work((rand() % 360) / 180.0 * pi);
  printf("%0.4lf\n", ans);
  flush();
  return 0;
}

T2 P6247 [SDOI2012]最近最远点对

思路:
最远点对随机到最远的点就行

代码:

#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 = 2e5 + 5;
const double INF = 1e15;
const double EPS = 1e-9;
const double pi = acos(-1);
inline int cp(double u, double v) {
  if (fabs(u - v) < EPS) return 0;
  return u > v ? 1 : -1;
}
int n;
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); }
  inline friend bool operator<(Point u, Point v) {
    if (cp(u.x, v.x)) return u.x < v.x;
    return u.y < v.y;
  }
} p[A];
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 Point rotate(Point u, double phi) {
  return Point(u.x * cos(phi) - u.y * sin(phi),
               u.x * sin(phi) + u.y * cos((phi)));
}

double ans1, ans2;

inline void work(double phi) {
  for (int i = 1; i <= n; i++) p[i] = rotate(p[i], phi);
  sort(p + 1, p + 1 + n);
  for (int i = 1; i < n; i++) {
    for (int j = 1; i + j <= n && j <= 5; j++)
      ans1 = min(ans1, dis(p[i], p[i + j]));
    for (int j = 1; n - j + 1 > i && j <= 5; j++)
      ans2 = max(ans2, dis(p[i], p[n - j + 1]));
  }
  return;
}

signed main() {
  srand(time(0));
  n = in();
  ans1 = INF, ans2 = -INF;
  for (int i = 1; i <= n; i++) scanf("%lf%lf", &p[i].x, &p[i].y);
  for (int i = 1; i <= 20; i++) work((rand() % 360) / 180.0 * pi);
  printf("%0.2lf %0.2lf\n", ans1, ans2);
  flush();
  return 0;
}

T3 Quoit Design

思路:
随机居然过不去……
我也是醉了

代码:

#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 = 2e5 + 5;
const double INF = 1e15;
const double EPS = 1e-7;
const double pi = acos(-1);
inline int cp(double u, double v) {
  if (fabs(u - v) < EPS) return 0;
  return u > v ? 1 : -1;
}
int n;
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], pp[A];
int tot;
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 bool cmp1(Point u, Point v) {
  if (cp(u.x, v.x)) return u.x < v.x;
  return u.y < v.y;
}

inline bool cmp2(Point u, Point v) {
  if (cp(u.y, v.y)) return u.y < v.y;
  return u.x < v.x;
}

double ans;

inline void work(int l, int r) {
  if (l == r) return;
  if (l + 1 == r) {
    ans = min(ans, dis(p[l], p[r]));
    return;
  }
  int mid = (l + r) >> 1;
  work(l, mid - 1), work(mid + 1, r);
  tot = 0;
  for (int i = mid; i >= l && cp(p[mid].x - p[i].x, ans) == -1; i--)
    pp[++tot] = p[i];
  for (int i = mid + 1; i <= r && cp(p[i].x - p[mid].x, ans) == -1; i++)
    pp[++tot] = p[i];
  sort(pp + 1, pp + 1 + tot, cmp2);
  for (int i = 1; i <= tot; i++)
    for (int j = i + 1; j <= tot && cp(pp[j].y - pp[i].y, ans) == -1; j++)
      ans = min(ans, dis(pp[i], pp[j]));
  return;
}

signed main() {
  n = in();
  while (n) {
    ans = INF;
    for (int i = 1; i <= n; i++) scanf("%lf%lf", &p[i].x, &p[i].y);
    sort(p + 1, p + 1 + n, cmp1);
    work(1, n);
    printf("%0.2lf\n", ans / 2);
    n = in();
  }
  flush();
  return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值