题目链接
题目大意:
给定 n 个点 m 个询问, 在给出一条线段,人从线段的st走到ed,每次询问查询第h个点在视野中发生第k次交换时人所处的位置。
思路:
先n2枚举预处理每组直线,二维结构体数组存直线与(路径)线段交点以及交点与(路径)线段起点的距离。
最后询问中可以采用对结构体h层进行nth_element查询(O(n) ), 或者可以对第h层sort(O(nlogn) );
注意坑点 k > n-1 输出 -1 ;
代码如下:
#include <iostream>
#include <cmath>
#include <algorithm>
#include <cstring>
using namespace std;
const double eps = 1e-8;
const double pi = acos(-1.0);
const double INF = 1e20;
int sgn(double x){
if(fabs(x) < eps) return 0;
return x < 0 ? -1 : 1;
}
struct Point{
double x, y;
Point(){}
Point(double x, double y) : x(x), y(y){}
void input(){scanf("%lf%lf", &x, &y);}
void output(){printf("%.8lf %.8lf\n", x, y);}
Point operator + (Point b){return Point(x+b.x, y+b.y);}
Point operator - (Point b){return Point(x-b.x, y-b.y);}
double operator ^ (Point b){
return x*b.y-y*b.x;
}
double dist(Point b){
return sqrt((x-b.x)*(x-b.x)+(y-b.y)*(y-b.y));
}
};
struct Line{
Point s, e;
double angle;
Line(){}
Line(Point s, Point e):s(s),e(e){}
int linecrossseg(Line v){
int d1 = sgn((e-s)^(v.s-s));
int d2 = sgn((e-s)^(v.e-s));
if((d1^d2)==-2) return 1;
else return 0;
}
Point crossline(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));
}
};
const int N = 1100;
Point p[N], st, ed;
struct node{
double d = INF;
Point co;
bool operator < (node v)const{
return d < v.d;
}
}dis[N][N];
int main(){
int n, m;
cin >> n >> m;
st.input(), ed.input();
Line L = Line(st, ed);
for(int i = 1;i <= n;i ++) p[i].input();
for(int i = 1;i <= n;i ++){
for(int j = i+1; j <= n;j ++){
Line v = Line(p[i], p[j]);
if(v.linecrossseg(L)){
Point co = v.crossline(L);
dis[i][j].d = st.dist(co);
dis[i][j].co = co;
dis[j][i].d = st.dist(co);
dis[j][i].co = co;
}
else{
dis[i][j].d = INF;
dis[j][i].d = INF;
}
}
}
while(m --){
int h, k;
scanf("%d%d", &h, &k);
if(k >= n){
puts("-1");
continue;
}
nth_element(dis[h]+1,dis[h] + k,dis[h] + n +1);
if(dis[h][k].d != INF){
dis[h][k].co.output();
}
else puts("-1");
}
return 0;
}
鲜有的计算几何铜牌题…