题意:
一个点走过一条线段,在线段的同一侧有许多点,随着点的移动,从线段上的这个点看这些点的视角会发生变化。目光可以看成一条直线,顺时针扫过整个平面,然后对于每个点进入视野的时间就会有先后顺序。问 m m m次对于最初的第 h h h个点第 k k k次交换位置的时候,此时线段上的点的位置坐标。
题解:
对于一个给定的点,与其他点会形成多条直线,我们可以求出这些直线与给定线段的交点。根据这些交点与线段起点的距离排序,交换 k k k次时所观察的坐标就是排序后第 k k k个交点的坐标。
实现细节见代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int MAXN = 1e6 + 10;
struct Point {
double x, y;
Point(){}
Point(double _x, double _y) {
x = _x;
y = _y;
}
Point operator - (const Point &b) const {
return Point(x - b.x, y - b.y);
}
double operator ^ (const Point &b) const {
return x * b.y - y * b.x;
}
}s, e, p[MAXN];
struct Line {
Point s, e;
Line(){}
Line(Point _s, Point _e) {
s = _s;
e = _e;
}
}line[MAXN];
Point get_line_intersection(Point p, Point v, Point q, Point w) {
auto u = p - q;
double t = (w ^ u) / (v ^ w);
return Point{p.x + v.x * t, p.y + v.y * t};
}
Point get_line_intersection(Line a, Line b) {
return get_line_intersection(a.s, a.e - a.s, b.s, b.e - b.s);
}
bool cmp(Point a, Point b) {
double len1 = hypot(a.x - s.x, a.y - s.y);
double len2 = hypot(b.x - s.x, b.y - s.y);
return len1 < len2;
}
Point all[MAXN];
int main() {
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int n, m;
cin >> n >> m;
cin >> s.x >> s.y >> e.x >> e.y;
int cnt = 0;
Line o{s, e};
for (int i = 1; i <= n; i++) {
cin >> p[i].x >> p[i].y;
}
while (m--) {
int h, k, num = 0;
cnt = 1;
cin >> h >> k;
for (int i = 1; i <= n; i++) {
if (i != h) {
Line now{p[h], p[i]};
Point cur = get_line_intersection(o, now);
if (cur.x < min(s.x, e.x) || cur.x > max(s.x, e.x) || cur.y < min(s.y, e.y) || cur.y > max(s.y, e.y)) continue; // 如果交点不在线段上不考虑
all[num++] = cur;
}
}
if (k > num) {
cout << -1 << endl;
continue;
}
sort(all, all + num, cmp);
cout << fixed << setprecision(10) << all[k - 1].x << " " << fixed << setprecision(10) << all[k - 1].y << endl;
}
return 0;
}