35pts求数据or求调(可怜)
查看原帖
35pts求数据or求调(可怜)
171169
Trilliverse楼主2024/8/17 14:58
// by trilliverse
#include <bits/stdc++.h>
using namespace std;

using ld = long double;

const double eps = 1e-8;
const double inf = 1e20;
const double pi = acos(-1.0);

int sgn(double x) {
    if (fabs(x) < eps)
        return 0;
    if (x < 0)
        return -1;
    else
        return 1;
}

struct Point {
    double x, y;
    Point() {}
    Point(double _x, double _y) : x(_x), y(_y) {}

    void input() { cin >> x >> y; }
    void output() { cerr << fixed << setprecision(5) << x << " " << y << '\n'; }

    bool operator==(Point b) const { return sgn(x - b.x) == 0 && sgn(y - b.y) == 0; }
    bool operator<(Point b) const { return sgn(x - b.x) == 0 ? sgn(y - b.y) < 0 : sgn(x - b.x) < 0; }
    Point operator+(const Point &b) const { return Point(x + b.x, y + b.y); }
    Point operator-(const Point &b) const { return Point(x - b.x, y - b.y); }
    Point operator*(const double &k) const { return Point(x * k, y * k); }
    Point operator/(const double &k) const { return Point(x / k, y / k); }

    double operator*(const Point &b) const { return x * b.x + y * b.y; }  // 点乘
    double operator^(const Point &b) const { return x * b.y - y * b.x; }  // 叉乘
    // 象限
    int quad() const {
        if (x > 0 && y >= 0)
            return 1;
        if (x <= 0 && y > 0)
            return 2;
        if (x < 0 && y <= 0)
            return 3;
        if (x >= 0 && y < 0)
            return 4;
        return 5;
    }
    double len() { return hypot(x, y); }  // 到原点的距离
    double len2() { return x * x + y * y; }
    double dis(Point b) { return hypot(x - b.x, y - b.y); }  // 两点间距离
    // pa ^ pb
    double cross(Point a, Point b) {
        Point p = {x, y};
        return (a - p) ^ (b - p);
    }
    // pa * pb
    double dot(Point a, Point b) {
        Point p = {x, y};
        return (a - p) * (b - p);
    }
    // 点p看a,b所成夹角 弧度制
    double rad(Point a, Point b) {
        Point p = *this;
        return fabs(atan2(fabs((a - p) ^ (b - p)), (a - p) * (b - p)));
    }
    // 角度制
    double ang(Point a, Point b) {
        return rad(a, b) / pi * 180.0;
    }
    Point rotleft() { return Point(-y, x); }   // 逆时针旋转90
    Point rotright() { return Point(y, -x); }  // 顺时针旋转90
    // 绕着点p逆时针旋转angle弧度
    Point rotate(Point p, double angle) {
        Point v = (*this) - p;
        double c = cos(angle);
        double s = sin(angle);
        return Point(p.x + v.x * c - v.y * s, p.y + v.x * s + v.y * c);
    }
};

struct Line {
    Point u, v;
    Line() {}
    Line(Point _u, Point _v) : u(_u), v(_v) {}
    bool operator==(Line l) { return (u == l.u) && (v == l.v); }

    // 点和倾斜角α确定直线 α∈[0, pi)
    Line(Point p, double angle) {
        u = p;
        if (sgn(angle - pi / 2) == 0)
            v = u + Point(0, 1);  // 斜率不存在
        else
            v = u + Point(1, tan(angle));
    }
    // ax+by+c=0
    Line(double a, double b, double c) {
        if (sgn(a) == 0) {
            u = Point(0, -c / b);
            v = Point(1, -c / b);
        } else if (sgn(b) == 0) {
            u = Point(-c / a, 0);
            v = Point(-c / a, 1);
        } else {
            u = Point(0, -c / b);
            v = Point(1, (-c - a) / b);
        }
    }

    void input() { u.input(), v.input(); }
    void adjust() {
        if (v < u)
            swap(u, v);
    }
    double len() { return u.dis(v); }  // 线段长度
    // 方向向量
    Point dir() { return v - u; }
    // 直线倾斜角 α∈[0, pi)
    double rad() {
        double theta = atan2(v.y - u.y, v.x - u.x);
        if (sgn(theta) < 0)
            theta += pi;
        if (sgn(theta - pi) == 0)
            theta -= pi;
        return theta;
    }
    // 点和直线(线段)关系
    // 1:左侧  2:右侧  3:线段上  4:线段前  5:线段后
    int relation(Point p) {
        int c = sgn((p - u) ^ (v - u));
        if (c < 0)
            return 1;
        else if (c > 0)
            return 2;
        else {  // on (line or segment)
            if (sgn((p - u) * (p - v)) <= 0)
                return 3;  // on segment
            if (sgn((p - u) * (v - u)) > 0)
                return 4;  // on line front
            else
                return 5;  // on line back
        }
    }

    // 直线与直线关系
    // 0:平行  1:重合  2:正交  3:其他
    int linecrossline(Line l) {
        if (sgn((v - u) * (l.v - l.u)) == 0)
            return 2;
        // 叉乘为0 → 共线向量(平行or重合)
        if (sgn((v - u) ^ (l.v - l.u)) == 0)
            return l.relation(u) > 2;
        return 3;
    }
    // 线段与线段关系
    // 2 规范相交 1 非规范相交 0 不相交
    int segcrossseg(Line l) {
        int d1 = sgn((v - u) ^ (l.u - u));
        int d2 = sgn((v - u) ^ (l.v - u));
        int d3 = sgn((l.v - l.u) ^ (u - l.u));
        int d4 = sgn((l.v - l.u) ^ (v - l.u));
        if ((d1 ^ d2) == -2 && (d3 ^ d4) == -2)
            return 2;
        return (d1 == 0 && sgn((l.u - u) * (l.u - v)) <= 0) ||
               (d2 == 0 && sgn((l.v - u) * (l.v - v)) <= 0) ||
               (d3 == 0 && sgn((u - l.u) * (u - l.v)) <= 0) ||
               (d4 == 0 && sgn((v - l.u) * (v - l.v)) <= 0);
    }
    // 直线与线段关系
    // *this:line; seg:segment
    // 2 规范相交 1 非规范相交 0 不相交
    int linecrossseg(Line seg) {
        int d1 = sgn((v - u) ^ (seg.u - u));
        int d2 = sgn((v - u) ^ (seg.v - u));
        if ((d1 ^ d2) == -2)
            return 2;
        return (d1 == 0 || d2 == 0);
    }
    // 求两直线交点 (要保证两直线不平行或重合)
    Point crosspoint(Line l) {
        double a1 = (l.v - l.u) ^ (u - l.u);
        double a2 = (l.v - l.u) ^ (v - l.u);
        Point p = {(u.x * a2 - v.x * a1) / (a2 - a1), (u.y * a2 - v.y * a1) / (a2 - a1)};
        p.x = fabs(p.x) < eps ? 0 : p.x;  // 可能会输出-0.00 特判
        p.y = fabs(p.y) < eps ? 0 : p.y;
        return p;
    }

    // 点到直线的距离
    double dispointtoline(Point p) {
        return fabs((p - u) ^ (v - u)) / len();
    }
    // 点到线段的距离
    double dispointtoseg(Point p) {
        if (sgn((p - u) * (v - u)) < 0 || sgn((p - v) * (u - v)) < 0)
            return min(p.dis(u), p.dis(v));
        return dispointtoline(p);
    }
    // 线段到线段的距离
    double dissegtoseg(Line l) {
        if (segcrossseg(l))
            return 0;  // 线段相交,距离就是0
        return min(min(dispointtoseg(l.u), dispointtoseg(l.v)),
                   min(l.dispointtoseg(u), l.dispointtoseg(v)));
    }

    // 点p在直线上的投影
    Point project(Point p) {
        return u + (((v - u) * ((v - u) * (p - u))) / ((v - u).len2()));
        // return p*
    }
    // 点p关于直线的对称点
    Point symmetry(Point p) {
        Point q = project(p);  // 连线中点
        return Point(2 * q.x - p.x, 2 * q.y - p.y);
    }
};

void solve() {
    Point o, d;
    o.input(), d.input();
    Line l = {o, o + d};  // 初始方向
    int n;
    cin >> n;
    vector<Line> seg(n + 1);  // 顺序无所谓
    vector<double> k(n + 1);
    for (int i = 1; i <= n; i++) {
        seg[i].input();
        double a, b;
        cin >> a >> b;
        k[i] = a / b;
    }
    vector<int> ans;
    for (int j = 1; j <= 10; j++) {
        double minn = inf;
        int id = 0;
        for (int i = 1; i <= n; i++) {
            Point s = seg[i].dir();
            if (sgn(s ^ d) == 0)
                continue;  // 平行或重合

            if (l.linecrossseg(seg[i]) == 0) {
                continue;  // 与线段不相交
            }
            Point t = l.crosspoint(seg[i]);
            // if(j == 2) t.output();
            int _ = l.relation(t);
            if (_ == 5)
                continue;
            if (d * (t - o) > 0) {
                double dis = o.dis(t);
                if (dis < minn) {
                    minn = dis;
                    id = i;
                }
            }
        }
        // if(j==2) cerr << id << '\n';
        if (id == 0)
            break;
        ans.push_back(id);
        Point t = l.crosspoint(seg[id]);
        // cerr << "j=" << j << " " << t.x << " " << t.y << "\n";
        if (l.linecrossline(seg[id]) == 2) {  // 垂直
            d = d * (-1);
        } else {
            Point segdir = seg[id].dir();  // 镜子方向向量
            if (sgn(d * segdir) < 0)
                segdir = segdir * (-1);
            // segdir.output();
            // t.output();
            double alpha = pi / 2 - o.rad(o + segdir, t);
            // cerr << "alpha=" << alpha*180/pi << '\n';
            double beta = k[id] * alpha;
            // // cerr << "beta=" << beta*180/pi << '\n';
            int op = sgn(segdir ^ d);
            // cerr << "op=" << op << '\n';
            // segdir.output();
            d = d * (-1);
            if (op == 1)
                d = d.rotate({0, 0}, (alpha + beta));
            else
                d = d.rotate({0, 0}, 2 * pi - alpha - beta);
        }
        o = t;
        l = {o, o + d};
        // o.output();
        // cerr << "d ";
        // d.output();
    }
    if (ans.size() == 0) {
        cout << "NONE\n";
    } else {
        for (int i = 0; i < ans.size(); i++) {
            cout << ans[i] << " \n"[i == ans.size() - 1];
        }
    }
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    solve();
    // cerr << clock() * 1.0 / CLOCKS_PER_SEC;
    return 0;
}
2024/8/17 14:58
加载中...