【LOJ】#2039. 「SHOI2015」激光发生器

题解

我永远都写不对计算几何……

首先找到反射的线段比较好找,扫一遍所有线段然后找交点在镜子上并且交点离起点最近的那条线段

然后旋转的时候,有可能是顺时针,也有可能是逆时针,要找出法线,然后判断法线和光线的角度然后确定顺时针逆时针

代码

#include <bits/stdc++.h>
#define enter putchar('\n')
#define space putchar(' ')
#define pii pair<int,int>
#define fi first
#define se second
#define MAXN 200005
#define pb push_back
#define eps 1e-8
//#define ivorysi
using namespace std;
typedef long long int64;
typedef double db;
template<class T>
void read(T &res) {
    res = 0;T f = 1;char c = getchar();
    while(c < '0' || c > '9') {
        if(c == '-') f = -1;
        c = getchar();
    }
    while(c >= '0' && c <= '9') {
        res = res * 10 + c - '0';
        c = getchar();
    }
    res *= f;
}
template<class T>
void out(T x) {
    if(x < 0) {x = -x;putchar('-');}
    if(x >= 10) out(x / 10);
    putchar('0' + x % 10);
}
bool dcmp(db a,db b) {
    return fabs(a - b) < eps;
}
struct Point {
    db x,y;
    Point(){}
    Point(db _x,db _y) {
        x = _x;y = _y;
    }
    friend Point operator + (const Point &a,const Point &b) {
        return Point(a.x + b.x,a.y + b.y);
    }
    friend Point operator - (const Point &a,const Point &b) {
        return Point(a.x - b.x,a.y - b.y);
    }
    friend Point operator * (const Point &a,const db &d) {
        return Point(a.x * d,a.y * d);
    }
    friend Point operator / (const Point &a,const db &d) {
        return Point(a.x / d,a.y / d);
    }
    friend db operator * (const Point &a,const Point &b) {
        return a.x * b.y - a.y * b.x;
    }
    friend db dot(const Point &a,const Point &b) {
        return a.x * b.x + a.y * b.y;
    }
    db norm() {
        return sqrt(x * x + y * y);
    }
};
struct Seg {
    Point a,b;db theta;
    Seg(){}
    Seg(Point _a,Point _b,db _theta = 0.0) {
        a = _a;b = _b;theta = _theta;
    }
    friend Point Cross_Point(const Seg &s,const Seg &t) {
        db S1 = (s.a - t.a) * (t.b - t.a);
        db S2 = (s.b - t.b) * (t.a - t.b);
        return s.a + (s.b - s.a) * (S1 / (S1 + S2));
    }
    bool in_Seg(Point P) {
        db d = (a - P) * (b - P);
        if(!dcmp(d,0.0)) return false;
        return  dot((a - P),(b - P)) <= eps;
    }
}S[105],L;
const db PI = acos(-1.0);
int N,ans[15],tot;
void Init() {
    db sx,sy,tx,ty,theta,a,b;
    scanf("%lf%lf%lf%lf",&sx,&sy,&tx,&ty);
    L = Seg(Point(sx,sy),Point(sx + tx,sy + ty));
    read(N);
    for(int i = 1 ; i <= N ; ++i) {
        scanf("%lf%lf%lf%lf%lf%lf",&sx,&sy,&tx,&ty,&a,&b);
        theta = a / b;
        S[i] = Seg(Point(sx,sy),Point(tx,ty),theta);
    }
}
void Solve() {
    int cnt = 10;
    while(cnt--) {
        int id = -1;Point t;
        for(int i = 1 ; i <= N ; ++i) {
            if(i == ans[tot]) continue;
            Point p = Cross_Point(L,S[i]);
            if(S[i].in_Seg(p) && dot(L.b - L.a,p - L.a) >= -eps) {
                if(id == -1) {id = i;t = p;}
                else if((p - L.a).norm() < (t - L.a).norm()) {
                    id = i;t = p;
                }
            }
        }
        if(id == -1) break;
        ans[++tot] = id;
        db d = dot(L.b - L.a,S[id].b - S[id].a);
        db alpha = acos(fabs(d) / ((L.b - L.a).norm() * (S[id].b - S[id].a).norm()));
        alpha = PI / 2 - alpha;
        alpha = (S[id].theta + 1) * alpha;
        L.b = L.a;L.a = t;
        Seg ver = Seg(t,t + Point(-(S[id].b - S[id].a).y,(S[id].b - S[id].a).x));
        if(dot(ver.b - ver.a,L.b - L.a) <= eps) {
            ver = Seg(t,t + Point((S[id].b - S[id].a).y,-(S[id].b - S[id].a).x));
        }
        Point tmp = L.b - t;
        if((ver.b - ver.a) * (L.b - L.a) >= -eps) alpha = -alpha;
        L.b = t + Point(tmp.x * cos(alpha) - tmp.y * sin(alpha),tmp.x * sin(alpha) + tmp.y * cos(alpha));
    }
    if(!tot) puts("NONE");
    else {
        for(int i = 1 ; i <= tot ; ++i) {
            out(ans[i]);space;
        }
        enter;
    }
}
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    Init();
    Solve();
    return 0;
}

转载于:https://www.cnblogs.com/ivorysi/p/9493825.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值