AOJ 1623 等積変形 (Equivalent Deformation)

解法

点を合わせる順番と対応を全部試して探索するだけで解ける.
点を合わせるときは,直接合わせられる場合は直接合わせればよいし,そうでない場合は残りの2点のどちらかを適切に移動させてから合わせればよい.このとき2点のどちらを選ぶかは両方試す.

ソースコード

#include <bits/stdc++.h>
using namespace std;

using ld = long double;
using point = complex<ld>;

constexpr ld eps = 1e-8;

struct line {
    point a, b;
};

bool eq(ld a, ld b) {
    return std::abs(a - b) < eps;
}

ld cross(point a, point b) {
    return imag(conj(a) * b);
}

bool isis_ll(point v1, point v2) {
    return !eq(cross(v1, v2), 0);
}

point is_ll(line s, line t) {
    point sv = s.b - s.a, tv = t.b - t.a;
    return s.a + sv * cross(tv, t.a - s.a) / cross(tv, sv);
}

int main() {
    vector<int> x1(3), y1(3);
    while(cin >> x1[0] >> y1[0]) {
        for(int i = 1; i < 3; ++i) cin >> x1[i] >> y1[i];
        vector<int> x2(3), y2(3);
        for(int i = 0; i < 3; ++i) cin >> x2[i] >> y2[i];

        function<int(int, vector<int>, vector<point>, int)> dfs = [&] (int i, vector<int> match, vector<point> ps, int step) {
            if(step >= 5 || i == 3) return step;
            auto vec = point(x2[match[i]], y2[match[i]]) - ps[i];
            auto p2 = ps[(i + 1) % 3], p3 = ps[(i + 2) % 3];
            auto vec2 = p2 - p3;
            if(!isis_ll(vec, vec2)) {
                ps[i] = point(x2[match[i]], y2[match[i]]);
                return dfs(i + 1, match, ps, step + 1);
            } else {
                int res = 5;
                {
                    auto tmp_ps = ps;
                    line l1{p2, p2 + ps[i] - p3};
                    line l2{p3, p3 + vec};
                    auto pp = is_ll(l1, l2);
                    tmp_ps[(i + 1) % 3] = pp;
                    tmp_ps[i] = point(x2[match[i]], y2[match[i]]);
                    res = min(res, dfs(i + 1, match, tmp_ps, step + 2));
                }
                {
                    auto tmp_ps = ps;
                    line l1{p3, p3 + ps[i] - p2};
                    line l2{p2, p2 + vec};
                    auto pp = is_ll(l1, l2);
                    tmp_ps[(i + 2) % 3] = pp;
                    tmp_ps[i] = point(x2[match[i]], y2[match[i]]);
                    res = min(res, dfs(i + 1, match, tmp_ps, step + 2));
                }
                return res;
            }
        };

        vector<int> ord(3);
        iota(ord.begin(), ord.end(), 0);
        int ans = 5;
        do {
            vector<int> match(3);
            iota(match.begin(), match.end(), 0);
            do {
                vector<point> ps(3);
                for(int i = 0; i < 3; ++i) ps[i] = point(x1[ord[i]], y1[ord[i]]);
                ans = min(ans, dfs(0, match, ps, 0));
            } while(next_permutation(match.begin(), match.end()));
        } while(next_permutation(ord.begin(), ord.end()));

        if(ans == 5) cout << "Many" << endl;
        else         cout << ans << endl;
    }
}

感想

こういうの,本番だと難しく見えるんですよね….