2020 ICPC 昆明站 I(Mr. Main and Windmills)

题目链接
题目大意:
给定 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;
}

鲜有的计算几何铜牌题…

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

marx97 ٩

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值