第 45 届国际大学生程序设计竞赛(ICPC)亚洲区域赛(昆明)-J. Mr. Main and Windmills【计算几何初步】

题目链接(牛客重现赛)
题意:给定一段路程(线段,起点S,终点T),在其一侧 n n n个点,对其中任意两个点来说,在从S到T的过程中对二者进行观测,有可能会发生左右位置的互换(一开始 p i p_i pi p j p_j pj左侧,后来 p i p_i pi p j p_j pj右侧),现在给你 m m m个询问:对于点 h i h_i hi,与其它点第 k i k_i ki次发生观测位置互换时,其坐标如何,如果不存在,输出"-1"。( 1 ≤ n ≤ 1000 , 1 ≤ m ≤ 1 0 4 1\le n\le1000,1\le m\le10^4 1n1000,1m104)
思路:显然对于每一次询问来说,假定当前点所在位置为 H H H,询问点为 P h i P_{h_i} Phi,直线 H P h i HP_{h_i} HPhi H H H移动的过程中扫过第 k i k_i ki个点时, H H H所在位置即为答案。当然,在这之前需要预处理,对每一个点 P x i P_{x_i} Pxi预处理它和其它所有点所在直线和 S T ST ST的交点,按到 S S S的距离排序即可。复杂度大概是 O ( n 2 l o g ( n ) ) O(n^2log(n)) O(n2log(n))

#include <bits/stdc++.h>
#define dsc(x) scanf("%d", &x)
#define rep(i, st, en) for (int i = st; i <= en; i++)
#define rrep(i, st, en) for (int i = st; i >= en; i--)
#define pb push_back
using namespace std;
const int N = 1E3 + 10;
const double eps = 1e-8;
double fabs(double x) {
  if (x < 0) return -x;
  return x;
}
int sgn(double x) {
  if (fabs(x) < eps) return 0;
  if (x < 0)
    return -1;
  else
    return 1;
}
struct Point {
  double x, y;
  int ind;
  Point() {}
  Point(double _x, double _y) {
    x = _x;
    y = _y;
    ind = 0;
  }
  void input() { scanf("%lf%lf", &x, &y); }
  void output() {
    if (sgn(x) == 0) x = 0;
    if (sgn(y) == 0) y = 0;
    printf("%.10f %.10f\n", x, y);
  }
  double operator^(const Point &B) { return x * B.y - y * B.x; }
  Point operator-(const Point &B) const { return Point(x - B.x, y - B.y); }
};
Point Now;
Point S, T, node[N];
struct Line {
  Point s, e;
  Line() {}
  Line(Point _s, Point _t) {
    s = _s;
    e = _t;
  }
  int relation(Point P) {
    int c = sgn((P - s) ^ (e - s));
    if (c < 0)
      return 1;
    else if (c < 0)
      return 2;
    else
      return 3;
  }
  int linecross(Line v) {//当前直线与线段v是否有交点,有交点返回2
    int d1 = sgn((e - s) ^ (v.s - s));
    int d2 = sgn((e - s) ^ (v.e - s));
    if ((d1 ^ d2) == -2) return 2;//有交点
    return (d1 == 0 || d2 == 0);
  }
  Point crosspoint(Line v) {
    double a1 = (v.e - v.s) ^ (s - v.s);
    double a2 = (v.e - v.s) ^ (e - v.s);
    return Point((s.x * a2 - e.x * a1) / (a2 - a1),
                 (s.y * a2 - e.y * a1) / (a2 - a1));
  }
  double Len() {
    return sqrt((e.x - s.x) * (e.x - s.x) + (e.y - s.y) * (e.y - s.y));
  }
};
bool cmp1(Point A, Point B) { return Line(S, A).Len() < Line(S, B).Len(); }
int main() {
  int n, m;
  dsc(n);
  dsc(m);
  vector<Point> v[n + 1];
  S.input();
  T.input();
  for (int i = 1; i <= n; i++) {
    node[i].input();
    node[i].ind = i;
  }
  Line st(S, T);

  rep(i, 1, n) {
    rep(j, 1, n) {
      if (i == j) continue;
      Line L1(node[i], node[j]);
      if (L1.linecross(st) != 2) continue;
      Point c = L1.crosspoint(st);
      v[i].push_back(c);
    }
    sort(v[i].begin(), v[i].end(), cmp1);
  }

  rep(i, 1, m) {
    int h, k, cnt = -1, now = 0;
    dsc(h);
    dsc(k);
    if (v[h].size() < k) {
      printf("-1\n");
      continue;
    }
    v[h][k - 1].output();
    // node[cnt] node[now]
  }
  return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值