algo — C++23 日本語リファレンス GitHub

test/aoj/challenge/2596.test.cpp

AC · 最終更新 2026-09-06 · GitHub

問題: https://onlinejudge.u-aizu.ac.jp/problems/2596

依存するヘッダ(1)
実装
// competitive-verifier: PROBLEM https://onlinejudge.u-aizu.ac.jp/problems/2596
// competitive-verifier: ERROR 0.00000001
#include <iomanip>
#include <iostream>
#include <stdexcept>
#include <string>
#include "parser/parser.hpp"

// Points and Lines: 唯一の左結合演算子 '@' が、被演算子の型 (点 or 直線) で
// 意味を変える式を評価する。点@点=2点を通る直線、直線@直線=交点、
// 点@直線/直線@点=直線に関する点の対称点。値型を「点 or 直線」の直和にした例。
// リテラルは常に "(X,Y)" (座標) か "(...)" (グループ化) なので、'(' の直後が
// 数字なら座標、'(' ならグループと判別できる。'(' は自前処理 (no_group)。
struct Val {
    bool is_point;
    double x, y;    // 点、または直線上の 1 点
    double dx, dy;  // 直線の方向ベクトル
};
using P = ExpressionParser<Val>;

static Val point(double x, double y) { return {true, x, y, 0, 0}; }

int main() {
    P p;
    p.binary("@", 10, P::Assoc::Left,
             [](const Val &a, const Val &b) -> Val {
                 if (a.is_point && b.is_point)  // 2 点を通る直線
                     return {false, a.x, a.y, b.x - a.x, b.y - a.y};
                 if (!a.is_point && !b.is_point) {  // 2 直線の交点
                     double den = a.dx * b.dy - a.dy * b.dx;
                     double s = ((b.x - a.x) * b.dy - (b.y - a.y) * b.dx) / den;
                     return point(a.x + s * a.dx, a.y + s * a.dy);
                 }
                 const Val &pt = a.is_point ? a : b;  // 直線に関する点の対称点
                 const Val &ln = a.is_point ? b : a;
                 double t = ((pt.x - ln.x) * ln.dx + (pt.y - ln.y) * ln.dy) / (ln.dx * ln.dx + ln.dy * ln.dy);
                 double fx = ln.x + t * ln.dx, fy = ln.y + t * ln.dy;
                 return point(2 * fx - pt.x, 2 * fy - pt.y);
             })
        .no_group()
        .atom([](P &q) -> Val {
            if (q.peek() != '(') throw std::runtime_error("expected (");
            q.advance();
            if (q.peek() == '(') {  // グループ化 "(" <expr> ")"
                Val v = q.parse_expression(0);
                if (!q.consume(")")) throw std::runtime_error("expected )");
                return v;
            }
            // 座標 "(" <number> "," <number> ")"
            auto num = [&q] {
                q.peek();
                double sign = 1;
                if (q.cur() == '-') sign = -1, q.advance();
                return sign * (double)q.read_uint();
            };
            double x = num();
            if (!q.consume(",")) throw std::runtime_error("expected ,");
            double y = num();
            if (!q.consume(")")) throw std::runtime_error("expected )");
            return point(x, y);
        });

    std::cout << std::fixed << std::setprecision(8);
    std::string s;
    while (std::getline(std::cin, s)) {
        if (s == "#") break;
        if (s.empty()) continue;
        Val r = p.parse(s);
        std::cout << r.x << ' ' << r.y << '\n';
    }
    return 0;
}