提出 #72331146


ソースコード 拡げる

#include <algorithm>
#include <array>
#include <bitset>
#include <chrono>
#include <cstdlib>
#include <iostream>
#include <queue>
#include <string>
#include <utility>
#include <vector>

using namespace std;

class Timer {
  public:
    Timer() : start_(chrono::high_resolution_clock::now()) {}
    void reset() { start_ = chrono::high_resolution_clock::now(); }
    long long elapsed_ms() const {
        auto now = chrono::high_resolution_clock::now();
        return chrono::duration_cast<chrono::milliseconds>(now - start_)
            .count();
    }

  private:
    chrono::high_resolution_clock::time_point start_;
};

constexpr int N = 20;
constexpr int BOARD_SIZE = N * N;
constexpr int CARD_TYPES = BOARD_SIZE / 2;
constexpr int OPEN_CANDS = 20;
constexpr int BEAM_LIMIT = 250;
constexpr long long TIME_LIMIT_MS = 1950;
constexpr int INF_INT = 1'000'000'000;

array<int, BOARD_SIZE> board_flat;
array<array<int, 2>, CARD_TYPES> card_cells;
array<int, BOARD_SIZE> row_of;
array<int, BOARD_SIZE> col_of;
array<array<uint16_t, BOARD_SIZE>, BOARD_SIZE> dist_matrix;

void build_dist_matrix();

inline int idx(int r, int c) { return r * N + c; }

inline int manhattan_idx(int a, int b) { return dist_matrix[a][b]; }

void build_dist_matrix() {
    for (int a = 0; a < BOARD_SIZE; ++a) {
        int ra = row_of[a];
        int ca = col_of[a];
        for (int b = 0; b < BOARD_SIZE; ++b) {
            int d = std::abs(ra - row_of[b]) + std::abs(ca - col_of[b]);
            dist_matrix[a][b] = static_cast<uint16_t>(d);
        }
    }
}

struct State {
    int id = -1;
    int depth = 0;  // visited cells
    int pos = 0;
    int move_cost = 0;
    int heuristic = 0;
    int parent = -1;
    int picked = -1;  // cell picked at this state
    bitset<BOARD_SIZE> taken;
    bitset<CARD_TYPES> on_stack;
    vector<int> stack;
    int score() const { return move_cost + heuristic; }
};

vector<State> states;

struct CompareState {
    bool operator()(int lhs, int rhs) const {
        const State& a = states[lhs];
        const State& b = states[rhs];
        if (a.score() != b.score()) return a.score() > b.score();  // min-heap
        return a.depth < b.depth;
    }
};

vector<priority_queue<int, vector<int>, CompareState>> beams(BOARD_SIZE + 1);
int best_state_id = -1;
Timer timer;

int calc_heuristic(const State& st) {
    // 1) resolve stack in LIFO order
    bitset<BOARD_SIZE> tmp_taken = st.taken;
    int pos = st.pos;
    int cost = 0;
    for (int i = static_cast<int>(st.stack.size()) - 1; i >= 0; --i) {
        int card = st.stack[i];
        int c0 = card_cells[card][0];
        int c1 = card_cells[card][1];
        int target = tmp_taken.test(c0) ? c1 : c0;
        cost += manhattan_idx(pos, target);
        pos = target;
        tmp_taken.set(target);
    }

    // 2) collect remaining complete pairs (both cells not taken)
    struct PairInfo {
        int c0, c1;
        int dist;
    };
    vector<PairInfo> pairs;
    pairs.reserve(CARD_TYPES);
    for (int card = 0; card < CARD_TYPES; ++card) {
        int c0 = card_cells[card][0];
        int c1 = card_cells[card][1];
        if (tmp_taken.test(c0) || tmp_taken.test(c1)) continue;
        int d01 = manhattan_idx(c0, c1);
        pairs.push_back({c0, c1, d01});
    }

    // 3) greedy visit for a limited number of pairs
    const int GREEDY_LIMIT = 20;
    int processed = 0;
    while (!pairs.empty() && processed < GREEDY_LIMIT) {
        int best_idx = -1;
        int best_to_first = INF_INT;
        bool go_to_c0 = true;
        for (int i = 0; i < static_cast<int>(pairs.size()); ++i) {
            int d0 = manhattan_idx(pos, pairs[i].c0);
            int d1 = manhattan_idx(pos, pairs[i].c1);
            if (d0 < best_to_first) {
                best_to_first = d0;
                best_idx = i;
                go_to_c0 = true;
            }
            if (d1 < best_to_first) {
                best_to_first = d1;
                best_idx = i;
                go_to_c0 = false;
            }
        }
        if (best_idx == -1) break;
        const PairInfo p = pairs[best_idx];
        cost += best_to_first + p.dist;
        pos = go_to_c0 ? p.c1 : p.c0;
        pairs[best_idx] = pairs.back();
        pairs.pop_back();
        processed++;
    }

    // 4) rough upper bound for remaining pairs
    int leftover_sum = 0;
    int nearest_leftover = INF_INT;
    for (const auto& p : pairs) {
        leftover_sum += p.dist;
        nearest_leftover = min(nearest_leftover, min(manhattan_idx(pos, p.c0),
                                                     manhattan_idx(pos, p.c1)));
    }
    if (nearest_leftover == INF_INT) nearest_leftover = 0;
    cost += leftover_sum + nearest_leftover;

    return cost;
}

bool better_state(int a, int b) {
    const State& x = states[a];
    const State& y = states[b];
    if (x.depth != y.depth) return x.depth > y.depth;
    if (x.stack.size() != y.stack.size())
        return x.stack.size() < y.stack.size();
    return x.move_cost < y.move_cost;
}

int other_cell(const State& st, int card) {
    int c0 = card_cells[card][0];
    int c1 = card_cells[card][1];
    if (!st.taken.test(c0)) return c0;
    if (!st.taken.test(c1)) return c1;
    return -1;
}

void prune(int depth) {
    auto& pq = beams[depth];
    if (static_cast<int>(pq.size()) <= BEAM_LIMIT) return;
    vector<int> keep;
    keep.reserve(BEAM_LIMIT);
    for (int i = 0; i < BEAM_LIMIT && !pq.empty(); i++) {
        keep.push_back(pq.top());
        pq.pop();
    }
    priority_queue<int, vector<int>, CompareState> npq(CompareState(),
                                                       std::move(keep));
    beams[depth].swap(npq);
}

void push_state(State st) {
    st.id = static_cast<int>(states.size());
    st.heuristic = calc_heuristic(st);
    int depth = st.depth;
    states.push_back(std::move(st));
    int sid = states.back().id;
    beams[depth].push(sid);
    prune(depth);
    if (best_state_id == -1 || better_state(sid, best_state_id))
        best_state_id = sid;
}

void expand(int sid) {
    // Snapshot because push_state can reallocate the states vector.
    const State cur = states[sid];
    if (cur.depth >= BOARD_SIZE) return;
    int next_depth = cur.depth + 1;

    // 1) Retrieve the pair for the top of the stack.
    if (!cur.stack.empty()) {
        int card = cur.stack.back();
        int target = other_cell(cur, card);
        if (target != -1) {
            State nxt = cur;
            nxt.parent = sid;
            nxt.picked = target;
            nxt.depth = next_depth;
            nxt.move_cost += manhattan_idx(cur.pos, target);
            nxt.pos = target;
            nxt.taken.set(target);
            nxt.stack.pop_back();
            nxt.on_stack.reset(card);
            push_state(std::move(nxt));
        }
    }

    // 2) Pick a new card that is not on the stack.
    vector<pair<int, int>> cand;
    cand.reserve(BOARD_SIZE - cur.depth);
    for (int i = 0; i < BOARD_SIZE; i++) {
        if (cur.taken.test(i)) continue;
        int card = board_flat[i];
        if (cur.on_stack.test(card)) continue;
        int dist = manhattan_idx(cur.pos, i);
        cand.push_back({dist, i});
    }
    if (!cand.empty()) {
        if (static_cast<int>(cand.size()) > OPEN_CANDS) {
            nth_element(
                cand.begin(), cand.begin() + OPEN_CANDS, cand.end(),
                [](const auto& a, const auto& b) { return a.first < b.first; });
            cand.resize(OPEN_CANDS);
        }
        sort(cand.begin(), cand.end(),
             [](const auto& a, const auto& b) { return a.first < b.first; });
        for (const auto& [dist, cell] : cand) {
            State nxt = cur;
            nxt.parent = sid;
            nxt.picked = cell;
            nxt.depth = next_depth;
            nxt.move_cost += dist;
            nxt.pos = cell;
            nxt.taken.set(cell);
            int card = board_flat[cell];
            nxt.stack.push_back(card);
            nxt.on_stack.set(card);
            push_state(std::move(nxt));
        }
    }
}

vector<int> reconstruct_path(int sid) {
    vector<int> path;
    int cur = sid;
    while (cur != -1) {
        const State& st = states[cur];
        if (st.picked != -1) path.push_back(st.picked);
        cur = st.parent;
    }
    reverse(path.begin(), path.end());
    return path;
}

vector<int> complete_path(State cur, vector<int> path) {
    while (cur.depth < BOARD_SIZE || !cur.stack.empty()) {
        if (!cur.stack.empty()) {
            int card = cur.stack.back();
            int target = other_cell(cur, card);
            if (target == -1) break;
            cur.move_cost += manhattan_idx(cur.pos, target);
            cur.pos = target;
            cur.taken.set(target);
            cur.stack.pop_back();
            cur.on_stack.reset(card);
            cur.depth++;
            path.push_back(target);
        } else {
            int best_cell = -1;
            int best_dist = INF_INT;
            for (int i = 0; i < BOARD_SIZE; i++) {
                if (cur.taken.test(i)) continue;
                int d = manhattan_idx(cur.pos, i);
                if (d < best_dist) {
                    best_dist = d;
                    best_cell = i;
                }
            }
            if (best_cell == -1) break;
            int card = board_flat[best_cell];
            cur.move_cost += best_dist;
            cur.pos = best_cell;
            cur.taken.set(best_cell);
            cur.stack.push_back(card);
            cur.on_stack.set(card);
            cur.depth++;
            path.push_back(best_cell);
        }
    }
    return path;
}

string build_operations(const vector<int>& path) {
    string ops;
    ops.reserve(BOARD_SIZE * 3);
    int cx = 0, cy = 0;
    vector<int> st;
    for (int cell : path) {
        int tx = row_of[cell];
        int ty = col_of[cell];
        while (cx < tx) {
            ops.push_back('D');
            cx++;
        }
        while (cx > tx) {
            ops.push_back('U');
            cx--;
        }
        while (cy < ty) {
            ops.push_back('R');
            cy++;
        }
        while (cy > ty) {
            ops.push_back('L');
            cy--;
        }
        ops.push_back('Z');
        int card = board_flat[cell];
        if (!st.empty() && st.back() == card) {
            st.pop_back();
        } else {
            st.push_back(card);
        }
    }
    return ops;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int n;
    if (!(cin >> n)) return 0;
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < N; j++) {
            int x;
            cin >> x;
            int id = idx(i, j);
            board_flat[id] = x;
            row_of[id] = i;
            col_of[id] = j;
        }
    }

    for (auto& v : card_cells) v.fill(-1);
    for (int i = 0; i < BOARD_SIZE; i++) {
        int c = board_flat[i];
        if (card_cells[c][0] == -1)
            card_cells[c][0] = i;
        else
            card_cells[c][1] = i;
    }
    build_dist_matrix();

    states.clear();
    best_state_id = -1;
    for (auto& pq : beams)
        pq = priority_queue<int, vector<int>, CompareState>();
    timer.reset();

    State root;
    root.pos = 0;
    root.depth = 0;
    push_state(root);

    while (timer.elapsed_ms() < TIME_LIMIT_MS) {
        for (int d = 0; d < BOARD_SIZE; d++) {
            if (timer.elapsed_ms() >= TIME_LIMIT_MS) break;
            if (beams[d].empty()) continue;
            int sid = beams[d].top();
            beams[d].pop();
            expand(sid);
        }
    }

    vector<int> path = reconstruct_path(best_state_id);
    path = complete_path(states[best_state_id], std::move(path));
    string ops = build_operations(path);

    for (char c : ops) cout << c << '\n';
    return 0;
}

提出情報

提出日時
問題 A - Stack to Match Pairs
ユーザ ruthen71
言語 C++23 (GCC 15.2.0)
得点 2276092
コード長 12222 Byte
結果 AC
実行時間 1970 ms
メモリ 145256 KiB

ジャッジ結果

セット名 test_ALL
得点 / 配点 2276092 / 2460000
結果
AC × 150
セット名 テストケース
test_ALL test_0000.txt, test_0001.txt, test_0002.txt, test_0003.txt, test_0004.txt, test_0005.txt, test_0006.txt, test_0007.txt, test_0008.txt, test_0009.txt, test_0010.txt, test_0011.txt, test_0012.txt, test_0013.txt, test_0014.txt, test_0015.txt, test_0016.txt, test_0017.txt, test_0018.txt, test_0019.txt, test_0020.txt, test_0021.txt, test_0022.txt, test_0023.txt, test_0024.txt, test_0025.txt, test_0026.txt, test_0027.txt, test_0028.txt, test_0029.txt, test_0030.txt, test_0031.txt, test_0032.txt, test_0033.txt, test_0034.txt, test_0035.txt, test_0036.txt, test_0037.txt, test_0038.txt, test_0039.txt, test_0040.txt, test_0041.txt, test_0042.txt, test_0043.txt, test_0044.txt, test_0045.txt, test_0046.txt, test_0047.txt, test_0048.txt, test_0049.txt, test_0050.txt, test_0051.txt, test_0052.txt, test_0053.txt, test_0054.txt, test_0055.txt, test_0056.txt, test_0057.txt, test_0058.txt, test_0059.txt, test_0060.txt, test_0061.txt, test_0062.txt, test_0063.txt, test_0064.txt, test_0065.txt, test_0066.txt, test_0067.txt, test_0068.txt, test_0069.txt, test_0070.txt, test_0071.txt, test_0072.txt, test_0073.txt, test_0074.txt, test_0075.txt, test_0076.txt, test_0077.txt, test_0078.txt, test_0079.txt, test_0080.txt, test_0081.txt, test_0082.txt, test_0083.txt, test_0084.txt, test_0085.txt, test_0086.txt, test_0087.txt, test_0088.txt, test_0089.txt, test_0090.txt, test_0091.txt, test_0092.txt, test_0093.txt, test_0094.txt, test_0095.txt, test_0096.txt, test_0097.txt, test_0098.txt, test_0099.txt, test_0100.txt, test_0101.txt, test_0102.txt, test_0103.txt, test_0104.txt, test_0105.txt, test_0106.txt, test_0107.txt, test_0108.txt, test_0109.txt, test_0110.txt, test_0111.txt, test_0112.txt, test_0113.txt, test_0114.txt, test_0115.txt, test_0116.txt, test_0117.txt, test_0118.txt, test_0119.txt, test_0120.txt, test_0121.txt, test_0122.txt, test_0123.txt, test_0124.txt, test_0125.txt, test_0126.txt, test_0127.txt, test_0128.txt, test_0129.txt, test_0130.txt, test_0131.txt, test_0132.txt, test_0133.txt, test_0134.txt, test_0135.txt, test_0136.txt, test_0137.txt, test_0138.txt, test_0139.txt, test_0140.txt, test_0141.txt, test_0142.txt, test_0143.txt, test_0144.txt, test_0145.txt, test_0146.txt, test_0147.txt, test_0148.txt, test_0149.txt
ケース名 結果 実行時間 メモリ
test_0000.txt AC 1968 ms 113192 KiB
test_0001.txt AC 1968 ms 111404 KiB
test_0002.txt AC 1967 ms 106960 KiB
test_0003.txt AC 1967 ms 113904 KiB
test_0004.txt AC 1967 ms 112392 KiB
test_0005.txt AC 1966 ms 109676 KiB
test_0006.txt AC 1968 ms 113564 KiB
test_0007.txt AC 1968 ms 124232 KiB
test_0008.txt AC 1967 ms 109640 KiB
test_0009.txt AC 1967 ms 111544 KiB
test_0010.txt AC 1968 ms 124832 KiB
test_0011.txt AC 1968 ms 118776 KiB
test_0012.txt AC 1969 ms 126940 KiB
test_0013.txt AC 1966 ms 95344 KiB
test_0014.txt AC 1969 ms 128268 KiB
test_0015.txt AC 1967 ms 122268 KiB
test_0016.txt AC 1968 ms 116852 KiB
test_0017.txt AC 1968 ms 115712 KiB
test_0018.txt AC 1968 ms 119280 KiB
test_0019.txt AC 1967 ms 110548 KiB
test_0020.txt AC 1968 ms 118128 KiB
test_0021.txt AC 1969 ms 133612 KiB
test_0022.txt AC 1968 ms 118444 KiB
test_0023.txt AC 1968 ms 113884 KiB
test_0024.txt AC 1967 ms 101328 KiB
test_0025.txt AC 1969 ms 120264 KiB
test_0026.txt AC 1966 ms 116444 KiB
test_0027.txt AC 1968 ms 116152 KiB
test_0028.txt AC 1969 ms 126556 KiB
test_0029.txt AC 1968 ms 113364 KiB
test_0030.txt AC 1969 ms 116656 KiB
test_0031.txt AC 1969 ms 125656 KiB
test_0032.txt AC 1969 ms 122184 KiB
test_0033.txt AC 1968 ms 108772 KiB
test_0034.txt AC 1967 ms 109840 KiB
test_0035.txt AC 1966 ms 103320 KiB
test_0036.txt AC 1968 ms 128060 KiB
test_0037.txt AC 1969 ms 122004 KiB
test_0038.txt AC 1970 ms 137400 KiB
test_0039.txt AC 1969 ms 123552 KiB
test_0040.txt AC 1967 ms 109204 KiB
test_0041.txt AC 1967 ms 104104 KiB
test_0042.txt AC 1968 ms 118928 KiB
test_0043.txt AC 1967 ms 108556 KiB
test_0044.txt AC 1968 ms 112776 KiB
test_0045.txt AC 1967 ms 110404 KiB
test_0046.txt AC 1967 ms 107488 KiB
test_0047.txt AC 1966 ms 107188 KiB
test_0048.txt AC 1966 ms 100192 KiB
test_0049.txt AC 1967 ms 116380 KiB
test_0050.txt AC 1965 ms 102356 KiB
test_0051.txt AC 1968 ms 121528 KiB
test_0052.txt AC 1967 ms 101728 KiB
test_0053.txt AC 1968 ms 120568 KiB
test_0054.txt AC 1966 ms 95156 KiB
test_0055.txt AC 1966 ms 107740 KiB
test_0056.txt AC 1967 ms 114620 KiB
test_0057.txt AC 1968 ms 117828 KiB
test_0058.txt AC 1969 ms 125228 KiB
test_0059.txt AC 1968 ms 115084 KiB
test_0060.txt AC 1968 ms 119944 KiB
test_0061.txt AC 1967 ms 112284 KiB
test_0062.txt AC 1968 ms 117576 KiB
test_0063.txt AC 1968 ms 114224 KiB
test_0064.txt AC 1968 ms 124128 KiB
test_0065.txt AC 1968 ms 119548 KiB
test_0066.txt AC 1970 ms 145256 KiB
test_0067.txt AC 1969 ms 126772 KiB
test_0068.txt AC 1968 ms 126152 KiB
test_0069.txt AC 1968 ms 120952 KiB
test_0070.txt AC 1966 ms 95964 KiB
test_0071.txt AC 1969 ms 122704 KiB
test_0072.txt AC 1968 ms 119432 KiB
test_0073.txt AC 1967 ms 120136 KiB
test_0074.txt AC 1966 ms 103120 KiB
test_0075.txt AC 1967 ms 112756 KiB
test_0076.txt AC 1968 ms 131904 KiB
test_0077.txt AC 1969 ms 139880 KiB
test_0078.txt AC 1967 ms 114584 KiB
test_0079.txt AC 1968 ms 125508 KiB
test_0080.txt AC 1967 ms 110800 KiB
test_0081.txt AC 1968 ms 120168 KiB
test_0082.txt AC 1969 ms 119152 KiB
test_0083.txt AC 1967 ms 111732 KiB
test_0084.txt AC 1968 ms 116368 KiB
test_0085.txt AC 1967 ms 118476 KiB
test_0086.txt AC 1969 ms 128380 KiB
test_0087.txt AC 1968 ms 118416 KiB
test_0088.txt AC 1966 ms 101044 KiB
test_0089.txt AC 1968 ms 119708 KiB
test_0090.txt AC 1969 ms 134052 KiB
test_0091.txt AC 1967 ms 116304 KiB
test_0092.txt AC 1968 ms 122220 KiB
test_0093.txt AC 1968 ms 122760 KiB
test_0094.txt AC 1968 ms 116464 KiB
test_0095.txt AC 1966 ms 104892 KiB
test_0096.txt AC 1966 ms 103508 KiB
test_0097.txt AC 1967 ms 119748 KiB
test_0098.txt AC 1967 ms 124552 KiB
test_0099.txt AC 1968 ms 125164 KiB
test_0100.txt AC 1968 ms 115200 KiB
test_0101.txt AC 1969 ms 133120 KiB
test_0102.txt AC 1967 ms 112864 KiB
test_0103.txt AC 1968 ms 120292 KiB
test_0104.txt AC 1967 ms 113280 KiB
test_0105.txt AC 1968 ms 118244 KiB
test_0106.txt AC 1968 ms 115664 KiB
test_0107.txt AC 1968 ms 116800 KiB
test_0108.txt AC 1967 ms 109300 KiB
test_0109.txt AC 1969 ms 127544 KiB
test_0110.txt AC 1967 ms 105340 KiB
test_0111.txt AC 1968 ms 112220 KiB
test_0112.txt AC 1968 ms 123700 KiB
test_0113.txt AC 1968 ms 125312 KiB
test_0114.txt AC 1968 ms 114348 KiB
test_0115.txt AC 1967 ms 106580 KiB
test_0116.txt AC 1966 ms 90992 KiB
test_0117.txt AC 1967 ms 110648 KiB
test_0118.txt AC 1968 ms 127932 KiB
test_0119.txt AC 1967 ms 108612 KiB
test_0120.txt AC 1968 ms 113760 KiB
test_0121.txt AC 1969 ms 119568 KiB
test_0122.txt AC 1968 ms 112292 KiB
test_0123.txt AC 1967 ms 104708 KiB
test_0124.txt AC 1968 ms 117792 KiB
test_0125.txt AC 1968 ms 122564 KiB
test_0126.txt AC 1967 ms 104012 KiB
test_0127.txt AC 1968 ms 123928 KiB
test_0128.txt AC 1968 ms 117920 KiB
test_0129.txt AC 1968 ms 115836 KiB
test_0130.txt AC 1966 ms 95244 KiB
test_0131.txt AC 1968 ms 125412 KiB
test_0132.txt AC 1969 ms 126976 KiB
test_0133.txt AC 1967 ms 114308 KiB
test_0134.txt AC 1967 ms 109388 KiB
test_0135.txt AC 1967 ms 118832 KiB
test_0136.txt AC 1967 ms 112148 KiB
test_0137.txt AC 1967 ms 114576 KiB
test_0138.txt AC 1966 ms 102776 KiB
test_0139.txt AC 1967 ms 111768 KiB
test_0140.txt AC 1967 ms 107180 KiB
test_0141.txt AC 1968 ms 119000 KiB
test_0142.txt AC 1966 ms 110220 KiB
test_0143.txt AC 1967 ms 109876 KiB
test_0144.txt AC 1968 ms 124420 KiB
test_0145.txt AC 1967 ms 115980 KiB
test_0146.txt AC 1966 ms 102380 KiB
test_0147.txt AC 1968 ms 123944 KiB
test_0148.txt AC 1967 ms 115916 KiB
test_0149.txt AC 1967 ms 118464 KiB