Submission #73749020


Source Code Expand

/*
 * solver_c.cpp - Problem C solver
 *
 * ── 問題設定 ──────────────────────────────────────────────
 *   N=20, AK=1000, AM=1, AW=1000 (壁コスト高 → 壁0枚)
 *   目標: 1台のロボット × 少ない状態数M で全400セルを巡回
 *   スコア = 1 + 1e6 * log2(base / V),  V = AK*(K-1) + AM*M
 *   → K=1, M小 が最高スコア。M=4で16,607,476, M=8で15,607,476
 *
 * ── 改善の道のり ──────────────────────────────────────────
 *   v1: SA + fallback (spinner robots)
 *       → Pass=~50/100, Avg=9.1M
 *       ボトルネック: SA探索空間が広すぎ、良い初期解がないと収束しない
 *
 *   v2: SA前にビームサーチ挿入 (M+1状態を系統的に探索)
 *       → Pass=43/100, SAの時間が減って逆効果
 *
 *   v3: SA廃止、ビームサーチ一本化
 *       → ビームサーチの候補数が爆発 (3×M×2×M per attachment)
 *       → M=6以降に到達できず Pass=43
 *
 *   v4: 単一位置評価 (17倍高速化)
 *       try_candでseedの最良位置1箇所だけsimulate → top候補のみfull eval
 *       → M=8まで到達可能に。Pass=53
 *
 *   v5: シードパターン多様化 (PatA/B/C/D)
 *       A: {0,2}=F, {1,3}=turn  B: {0,3}=F, {1,2}=turn
 *       C: {0,1}=F, {2,3}=turn  D: {1,2}=F, {0,3}=turn
 *       → Pass=61, Avg=11.9M
 *
 *   v6: チームメイトのv9_cからハードコードシード導入
 *       8種ジグザグ(M=4) + 壁追従(M=4) + ゴールデンパターン(M=5,6)
 *       事前検証済みの高品質パターンをfull evalしてシードに
 *       → Pass=94, Avg=15.8M  ← 現在
 *
 * ── 現在のアーキテクチャ ──────────────────────────────────
 *   Phase 0: ハードコードシード (14パターン × 全1600開始位置)  ~0.16s
 *   Phase 1: パターン列挙 (A/B/C/D) M=4シード生成              ~0.30s
 *   Phase 2: ビームサーチ M=5→8
 *            - 各レベルで親シードの遷移1本を新状態に繋ぎ替え
 *            - 新状態の(a0,b0,a1,b1)を全列挙
 *            - 単一位置評価で高速フィルタ → top-50 → top-20 full eval
 *            - ビーム幅: M=5:60, M=6:50, M=7:35, M=8:20          ~1.40s
 *   Fallback: best partial + 未カバーセルにspinner robot (M=1回転)
 *
 * ── 残課題 ────────────────────────────────────────────────
 *   - 6/100ケースがフォールバック (5件はuncov=1-2, 1件はuncov=20)
 *   - 乱数シード変更やSA追加で拾える可能性あり
 *   - ビームサーチの評価関数に距離ペナルティ導入で改善余地
 */

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <random>
#include <chrono>
using namespace std;

const int N = 20;                           // グリッドサイズ (Problem Cは常に20)
const int DI[] = {-1, 0, 1, 0};             // 方向: U=0, R=1, D=2, L=3
const int DJ[] = {0, 1, 0, -1};
const char DIR_CH[] = {'U', 'R', 'D', 'L'};
const char* ACT_STR[] = {"F", "R", "L"};    // アクション: 0=前進, 1=右回転, 2=左回転

int wall_v[N][N], wall_h[N][N];

auto t0 = chrono::steady_clock::now();
double elapsed() {
    return chrono::duration<double>(chrono::steady_clock::now() - t0).count();
}

inline bool has_wall(int r, int c, int d) {
    if (d == 0) return r == 0 || wall_h[r-1][c];
    if (d == 2) return r == N-1 || wall_h[r][c];
    if (d == 1) return c == N-1 || wall_v[r][c];
    return c == 0 || wall_v[r][c-1];
}

// オートマトン: M状態、各状態sに対し
//   壁なし: アクション a0[s], 遷移先 b0[s]
//   壁あり: アクション a1[s], 遷移先 b1[s]
// 最大8状態 (M=4のジグザグ → ビームでM=8まで拡張)
struct Automaton {
    int M;
    int a0[8], b0[8];  // no-wall: action, next_state
    int a1[8], b1[8];  // wall:    action, next_state
};

// サイクル検出用の世代管理配列 (simulate/simulate_cellsで共用)
// キー: (row*N+col)*4+dir)*M+state → 最大 20*20*4*8 = 12800
static int g_fv_gen[N * N * 4 * 8];  // 訪問世代
static int g_fv_val[N * N * 4 * 8];  // 訪問ステップ番号
static int g_gen = 0;                // 現在の世代 (毎simulate呼び出しでインクリメント)

// シミュレーション: 開始位置(si,sj,sd)からサイクルに入るまで実行し、
// サイクル内で訪問するユニークセル数を返す。~2μs/call
int simulate(const Automaton& aut, int si, int sj, int sd) {
    g_gen++;
    int m = aut.M;
    int r = si, c = sj, d = sd, s = 0;
    int max_steps = N * N * 4 * m;
    for (int step = 0; step <= max_steps; step++) {
        int enc = ((r * N + c) * 4 + d) * m + s;
        if (g_fv_gen[enc] == g_gen) {
            int cycle_start = g_fv_val[enc];
            bool seen[N][N] = {};
            int cnt = 0;
            int r2 = si, c2 = sj, d2 = sd, s2 = 0;
            for (int t = 0; t < step; t++) {
                if (t >= cycle_start && !seen[r2][c2]) { seen[r2][c2] = true; cnt++; }
                bool w = has_wall(r2, c2, d2);
                int act = w ? aut.a1[s2] : aut.a0[s2];
                int nxt = w ? aut.b1[s2] : aut.b0[s2];
                if (act == 0) { r2 += DI[d2]; c2 += DJ[d2]; }
                else if (act == 1) d2 = (d2 + 1) % 4;
                else d2 = (d2 + 3) % 4;
                s2 = nxt;
            }
            return cnt;
        }
        g_fv_gen[enc] = g_gen;
        g_fv_val[enc] = step;
        bool w = has_wall(r, c, d);
        int act = w ? aut.a1[s] : aut.a0[s];
        int nxt = w ? aut.b1[s] : aut.b0[s];
        if (act == 0) { r += DI[d]; c += DJ[d]; }
        else if (act == 1) d = (d + 1) % 4;
        else d = (d + 3) % 4;
        s = nxt;
    }
    return 0;
}

// カバーセル取得: サイクル内で訪問するセルをcovered[][]に記録 (フォールバック用)
void simulate_cells(const Automaton& aut, int si, int sj, int sd, bool covered[N][N]) {
    g_gen++;
    memset(covered, 0, sizeof(bool)*N*N);
    int m = aut.M;
    int r = si, c = sj, d = sd, s = 0;
    int max_steps = N * N * 4 * m;
    for (int step = 0; step <= max_steps; step++) {
        int enc = ((r * N + c) * 4 + d) * m + s;
        if (g_fv_gen[enc] == g_gen) {
            int cycle_start = g_fv_val[enc];
            int r2 = si, c2 = sj, d2 = sd, s2 = 0;
            for (int t = 0; t < step; t++) {
                if (t >= cycle_start) covered[r2][c2] = true;
                bool w = has_wall(r2, c2, d2);
                int act = w ? aut.a1[s2] : aut.a0[s2];
                int nxt = w ? aut.b1[s2] : aut.b0[s2];
                if (act == 0) { r2 += DI[d2]; c2 += DJ[d2]; }
                else if (act == 1) d2 = (d2 + 1) % 4;
                else d2 = (d2 + 3) % 4;
                s2 = nxt;
            }
            return;
        }
        g_fv_gen[enc] = g_gen;
        g_fv_val[enc] = step;
        bool w = has_wall(r, c, d);
        int act = w ? aut.a1[s] : aut.a0[s];
        int nxt = w ? aut.b1[s] : aut.b0[s];
        if (act == 0) { r += DI[d]; c += DJ[d]; }
        else if (act == 1) d = (d + 1) % 4;
        else d = (d + 3) % 4;
        s = nxt;
    }
}

struct Result { int cov, si, sj, sd; };

// 全1600開始位置 (20×20×4方向) を試して最良カバレッジを返す。~3.2ms/call
Result best_start(const Automaton& aut) {
    Result best = {0, 0, 0, 0};
    for (int i = 0; i < N; i++)
    for (int j = 0; j < N; j++)
    for (int d = 0; d < 4; d++) {
        int c = simulate(aut, i, j, d);
        if (c > best.cov) { best = {c, i, j, d}; if (c == N*N) return best; }
    }
    return best;
}

// 候補: オートマトン + そのベスト開始位置でのカバレッジ
struct Cand { Automaton aut; int cov, si, sj, sd; };

int main() {
    int n, ak, am, aw;
    scanf("%d%d%d%d", &n, &ak, &am, &aw);
    fprintf(stderr, "N=%d AK=%d AM=%d AW=%d\n", n, ak, am, aw);

    for (int i = 0; i < N; i++) {
        char s[32]; scanf("%s", s);
        for (int j = 0; j < N-1; j++) wall_v[i][j] = s[j] - '0';
    }
    for (int i = 0; i < N-1; i++) {
        char s[32]; scanf("%s", s);
        for (int j = 0; j < N; j++) wall_h[i][j] = s[j] - '0';
    }
    t0 = chrono::steady_clock::now();
    mt19937 rng(42);

    Cand global_best = {{}, 0, 0, 0, 0};
    vector<Cand> top_seeds;

    // ビームサーチ用: seedの最良位置1箇所だけでsimulate (高速、~2μs)
    // seed.cov-10以上なら候補に追加。full evalはバッチで後からやる
    auto try_cand = [&](Automaton& ext, const Cand& seed, vector<Cand>& cands) -> bool {
        int q = simulate(ext, seed.si, seed.sj, seed.sd);
        if (q >= seed.cov - 10)
            cands.push_back({ext, q, seed.si, seed.sj, seed.sd});
        return false; // never short-circuit; batch full-eval at end
    };

    // シード列挙用: 粗いグリッド (5刻み×4方向=64点) で評価
    // cov≥80ならシード追加、global_bestより良ければfull eval
    auto try_seed = [&](Automaton a) -> bool {
        int q = simulate(a, 0, 0, 1);
        if (q < 50) return false;
        int best_q = q; int bi=0, bj=0, bd=1;
        for (int pi = 0; pi < N; pi += 5)
        for (int pj = 0; pj < N; pj += 5)
        for (int pd = 0; pd < 4; pd++) {
            int c = simulate(a, pi, pj, pd);
            if (c > best_q) { best_q = c; bi=pi; bj=pj; bd=pd; }
        }
        if (best_q >= 80)
            top_seeds.push_back({a, best_q, bi, bj, bd});
        if (best_q > global_best.cov) {
            auto res = best_start(a);
            if (res.cov > global_best.cov)
                global_best = {a, res.cov, res.si, res.sj, res.sd};
            if (res.cov == N*N) return true;
        }
        return false;
    };

    // ============================================================
    // Phase 0: ハードコードシード (チームメイトv9_cから)
    //   事前検証済みの高品質パターンをfull eval (全1600位置)
    //   27パターン × 3.2ms = ~0.09s。大半のケースはここで解決
    // ============================================================
    {
        // 21 unique automata mined from 94/100 successful runs on inC/0000-0099
        // + wall followers + v9_c templates. Sorted by M.
        Automaton hc_all[] = {
            // M=4: 7 patterns (5 zigzag classes + 2 wall followers)
            {4, {0,2,0,1}, {1,2,3,0}, {1,2,1,2}, {0,0,2,2}},  // zigzag class 1
            {4, {0,2,0,1}, {1,2,3,0}, {2,2,1,1}, {2,0,2,0}},  // zigzag class 2
            {4, {0,2,1,0}, {2,0,3,1}, {1,2,1,2}, {3,3,0,0}},  // zigzag class 3
            {4, {0,1,0,2}, {1,2,3,0}, {2,1,2,1}, {0,0,2,2}},  // mirror 1
            {4, {0,1,0,2}, {1,2,3,0}, {1,1,2,2}, {2,0,2,0}},  // mirror 2
            {4, {1,0,0,0}, {1,0,0,0}, {1,2,2,2}, {1,2,3,0}},  // right wall follower
            {4, {2,0,0,0}, {1,0,0,0}, {2,1,1,1}, {1,2,3,0}},  // left wall follower
            // M=5: 10 patterns (beam search discoveries)
            {5, {0,2,0,1,1,0,0,0}, {1,2,3,0,1,0,0,0}, {2,2,1,1,1,0,0,0}, {2,0,4,0,2,0,0,0}},
            {5, {0,1,0,2,2,0,0,0}, {1,2,3,0,1,0,0,0}, {1,1,2,2,2,0,0,0}, {2,0,4,0,2,0,0,0}},
            {5, {0,2,0,1,1,0,0,0}, {1,2,3,0,1,0,0,0}, {2,2,1,1,1,0,0,0}, {2,0,4,0,1,0,0,0}},
            {5, {0,1,0,2,2,0,0,0}, {1,2,3,0,4,0,0,0}, {2,1,2,1,2,0,0,0}, {4,0,2,2,0,0,0,0}},
            {5, {0,1,0,2,2,0,0,0}, {1,2,3,0,1,0,0,0}, {1,1,2,2,2,0,0,0}, {2,0,4,0,1,0,0,0}},
            {5, {0,2,1,0,2,0,0,0}, {2,0,3,1,4,0,0,0}, {1,2,1,2,2,0,0,0}, {3,4,0,0,3,0,0,0}},
            {5, {0,1,0,2,2,0,0,0}, {1,2,3,0,1,0,0,0}, {1,1,2,2,2,0,0,0}, {2,0,4,0,4,0,0,0}},
            {5, {0,2,0,1,1,0,0,0}, {1,2,3,0,1,0,0,0}, {2,2,1,1,1,0,0,0}, {2,0,4,0,4,0,0,0}},
            {5, {0,2,0,1,2,0,0,0}, {1,2,3,0,4,0,0,0}, {1,2,1,2,2,0,0,0}, {0,0,2,4,2,0,0,0}},
            {5, {0,2,0,1,0,0,0,0}, {1,2,3,0,2,0,0,0}, {2,2,1,1,2,0,0,0}, {4,0,2,0,2,0,0,0}},
            // M=6: 5 patterns (golden patterns + beam discoveries)
            {6, {0,2,0,1,1,0,0,0}, {1,2,3,0,5,5,0,0}, {1,2,1,2,1,1,0,0}, {4,0,2,2,5,0,0,0}},
            {6, {0,1,0,2,2,0,0,0}, {1,2,3,0,5,5,0,0}, {2,1,2,1,2,2,0,0}, {4,0,2,2,5,0,0,0}},
            {6, {0,1,0,2,0,1,0,0}, {1,2,3,0,5,4,0,0}, {2,1,2,1,2,1,0,0}, {0,4,2,2,4,0,0,0}},
            {6, {0,2,1,0,1,1,0,0}, {2,0,3,1,4,5,0,0}, {1,2,1,2,1,1,0,0}, {4,3,5,0,3,0,0,0}},
            {6, {0,2,1,0,1,2,0,0}, {2,0,3,1,4,5,0,0}, {1,2,1,2,1,2,0,0}, {4,3,0,5,3,0,0,0}},
            // M=7: 2 patterns
            {7, {0,2,0,1,1,0,2,0}, {1,2,3,0,5,5,6,0}, {1,2,1,2,1,1,2,0}, {4,0,2,6,5,0,2,0}},
            {7, {0,2,0,1,1,0,2,0}, {1,2,3,0,5,5,6,0}, {1,2,1,2,1,1,2,0}, {4,6,2,2,5,0,0,0}},  // from 0016
        };
        // Also keep v9_c templates not already in mined set
        Automaton hc_extra[] = {
            {4, {0,1,2,0}, {2,0,3,1}, {2,1,2,1}, {3,3,0,0}},  // mirror 3
            {4, {0,2,1,0}, {2,0,3,1}, {2,1,2,1}, {3,3,0,0}},  // wall swap 1
            {4, {0,2,1,0}, {2,0,3,1}, {1,2,1,2}, {0,0,0,0}},  // wall swap 2
            {5, {0,1,0,2,1,0,0,0}, {1,2,3,0,4,0,0,0}, {2,1,2,1,1,0,0,0}, {0,0,2,4,2,0,0,0}},
        };

        auto full_seed = [&](Automaton& a) {
            auto res = best_start(a);
            if (res.cov >= 50) {
                top_seeds.push_back({a, res.cov, res.si, res.sj, res.sd});
                if (res.cov > global_best.cov)
                    global_best = {a, res.cov, res.si, res.sj, res.sd};
            }
            return res.cov == N*N;
        };

        for (auto& a : hc_all)   if (full_seed(a)) { fprintf(stderr, "HC found! M=%d\n", a.M); goto output; }
        for (auto& a : hc_extra) if (full_seed(a)) { fprintf(stderr, "HC extra found! M=%d\n", a.M); goto output; }
        fprintf(stderr, "[%.2fs] Hardcoded seeds: %d added, best=%d\n",
                elapsed(), (int)top_seeds.size(), global_best.cov);

    }

    // ============================================================
    // Phase 1: パターン列挙でM=4シード生成
    //   4つのF位置パターン (A/B/C/D) × 壁遷移全列挙
    //   時間制限付き (各パターン0.05-0.10s)
    //   ハードコードで拾えなかったケース用の多様なシード確保
    // ============================================================

    // Pattern A: state {0,2}=前進, {1,3}=回転。古典的ジグザグ型
    {
        int cnt = 0;
        for (int t1 = 1; t1 <= 2; t1++)
        for (int t3 = 1; t3 <= 2; t3++)
        for (int b00 : {1,3}) for (int b01 : {0,2})
        for (int b02 : {1,3}) for (int b03 : {0,2})
        for (int w0 = 1; w0 <= 2; w0++) for (int w1 = 1; w1 <= 2; w1++)
        for (int w2 = 1; w2 <= 2; w2++) for (int w3 = 1; w3 <= 2; w3++)
        for (int wb0 : {0,1,2,3}) for (int wb1 : {0,1,2,3})
        for (int wb2 : {0,1,2,3}) for (int wb3 : {0,1,2,3}) {
            cnt++;
            Automaton a = {4, {0,t1,0,t3}, {b00,b01,b02,b03},
                              {w0,w1,w2,w3}, {wb0,wb1,wb2,wb3}};
            if (try_seed(a) && global_best.cov == N*N) {
                fprintf(stderr, "[%.2fs] Seed full coverage M=4 (patA)!\n", elapsed());
                goto output;
            }
            if (elapsed() > 0.10) goto patA_done;
        }
        patA_done:
        fprintf(stderr, "[%.2fs] PatA: %d enumerated\n", elapsed(), cnt);
    }

    // Pattern B: state {0,3}=前進, {1,2}=回転。交差配線型
    {
        int cnt = 0;
        for (int t1 = 1; t1 <= 2; t1++)
        for (int t2 = 1; t2 <= 2; t2++)
        for (int b00 : {1,2}) for (int b01 : {0,3})
        for (int b02 : {0,3}) for (int b03 : {1,2})
        for (int w0 = 1; w0 <= 2; w0++) for (int w1 = 1; w1 <= 2; w1++)
        for (int w2 = 1; w2 <= 2; w2++) for (int w3 = 1; w3 <= 2; w3++)
        for (int wb0 : {0,1,2,3}) for (int wb1 : {0,1,2,3})
        for (int wb2 : {0,1,2,3}) for (int wb3 : {0,1,2,3}) {
            cnt++;
            Automaton a = {4, {0,t1,t2,0}, {b00,b01,b02,b03},
                              {w0,w1,w2,w3}, {wb0,wb1,wb2,wb3}};
            if (try_seed(a) && global_best.cov == N*N) {
                fprintf(stderr, "[%.2fs] Seed full coverage M=4 (patB)!\n", elapsed());
                goto output;
            }
            if (elapsed() > 0.20) goto patB_done;
        }
        patB_done:
        fprintf(stderr, "[%.2fs] PatB: %d enumerated\n", elapsed(), cnt);
    }

    // Pattern C: state {0,1}=前進, {2,3}=回転。連続前進型
    {
        int cnt = 0;
        for (int t2 = 1; t2 <= 2; t2++)
        for (int t3 = 1; t3 <= 2; t3++)
        for (int b00 : {0,1,2,3}) for (int b01 : {0,1,2,3})
        for (int b02 : {0,1,2,3}) for (int b03 : {0,1,2,3})
        for (int w0 = 1; w0 <= 2; w0++) for (int w1 = 1; w1 <= 2; w1++)
        for (int w2 = 1; w2 <= 2; w2++) for (int w3 = 1; w3 <= 2; w3++)
        for (int wb0 : {0,1,2,3}) for (int wb1 : {0,1,2,3})
        for (int wb2 : {0,1,2,3}) for (int wb3 : {0,1,2,3}) {
            cnt++;
            Automaton a = {4, {0,0,t2,t3}, {b00,b01,b02,b03},
                              {w0,w1,w2,w3}, {wb0,wb1,wb2,wb3}};
            if (try_seed(a) && global_best.cov == N*N) {
                fprintf(stderr, "[%.2fs] Seed full coverage M=4 (patC)!\n", elapsed());
                goto output;
            }
            if (elapsed() > 0.25) goto patC_done;
        }
        patC_done:
        fprintf(stderr, "[%.2fs] PatC: %d enumerated\n", elapsed(), cnt);
    }

    // Pattern D: state {1,2}=前進, {0,3}=回転。中央前進型
    {
        int cnt = 0;
        for (int t0 = 1; t0 <= 2; t0++)
        for (int t3 = 1; t3 <= 2; t3++)
        for (int b00 : {0,1,2,3}) for (int b01 : {0,1,2,3})
        for (int b02 : {0,1,2,3}) for (int b03 : {0,1,2,3})
        for (int w0 = 1; w0 <= 2; w0++) for (int w1 = 1; w1 <= 2; w1++)
        for (int w2 = 1; w2 <= 2; w2++) for (int w3 = 1; w3 <= 2; w3++)
        for (int wb0 : {0,1,2,3}) for (int wb1 : {0,1,2,3})
        for (int wb2 : {0,1,2,3}) for (int wb3 : {0,1,2,3}) {
            cnt++;
            Automaton a = {4, {t0,0,0,t3}, {b00,b01,b02,b03},
                              {w0,w1,w2,w3}, {wb0,wb1,wb2,wb3}};
            if (try_seed(a) && global_best.cov == N*N) {
                fprintf(stderr, "[%.2fs] Seed full coverage M=4 (patD)!\n", elapsed());
                goto output;
            }
            if (elapsed() > 0.30) goto patD_done;
        }
        patD_done:
        fprintf(stderr, "[%.2fs] PatD: %d enumerated\n", elapsed(), cnt);
    }

    // シードをカバレッジ降順でソートし、上位80個に絞る
    sort(top_seeds.begin(), top_seeds.end(),
         [](const Cand& a, const Cand& b) { return a.cov > b.cov; });
    if ((int)top_seeds.size() > 80) top_seeds.resize(80);
    fprintf(stderr, "[%.2fs] Total seeds: %d, best=%d M=%d\n",
            elapsed(), (int)top_seeds.size(), global_best.cov, global_best.aut.M);

    // ============================================================
    // Phase 2: ビームサーチ (M=5→8)
    //   親シードの遷移1本を新状態new_sに繋ぎ替え、
    //   new_sの(a0,b0,a1,b1)を全列挙 → 単一位置評価でフィルタ
    //   候補数/seed: 2M attachments × 3×M×2×M = 12M³
    //   M=5: 1500/seed, M=6: 2160/seed (単一位置eval → ~2μs/候補)
    //   ビーム幅を段階的に縮小: M=5:60, M=6:50, M=7:35, M=8:20
    // ============================================================

    // M=4シードの正確な評価 (Phase 0で粗評価のものをfull eval)
    {
        for (int i = 0; i < min(20, (int)top_seeds.size()) && elapsed() < 0.40; i++) {
            if (top_seeds[i].aut.M != 4) continue;
            auto res = best_start(top_seeds[i].aut);
            top_seeds[i].cov = res.cov;
            top_seeds[i].si = res.si; top_seeds[i].sj = res.sj; top_seeds[i].sd = res.sd;
            if (res.cov > global_best.cov) global_best = top_seeds[i];
            if (res.cov == N*N) {
                fprintf(stderr, "  FOUND M=4!\n");
                goto output;
            }
        }
        sort(top_seeds.begin(), top_seeds.end(),
             [](const Cand& a, const Cand& b) { return a.cov > b.cov; });
        fprintf(stderr, "[%.2fs] M=4 full eval done, best=%d\n", elapsed(), global_best.cov);
    }

    // M+1ビームサーチ本体: 各Mレベルで新状態を1つ追加して全列挙
    {
        static const int max_seeds[] = {0,0,0,0,0, 60, 50, 35, 20};
        for (int target_m = 5; target_m <= 8 && elapsed() < 1.85; target_m++) {
            int n_prev = 0;
            for (auto& s : top_seeds) if (s.aut.M == target_m - 1) n_prev++;
            if (n_prev == 0) continue;
            int use_seeds = min(n_prev, max_seeds[target_m]);

            fprintf(stderr, "[%.2fs] === Beam M=%d (using %d/%d seeds) ===\n",
                    elapsed(), target_m, use_seeds, n_prev);
            int new_s = target_m - 1;
            vector<Cand> next_cands;
            int seed_cnt = 0;

            for (auto& seed : top_seeds) {
                if (seed.aut.M != target_m - 1) continue;
                if (++seed_cnt > use_seeds) break;
                if (elapsed() > 1.85) break;

                for (int from = 0; from < seed.aut.M && elapsed() < 1.85; from++) {
                    for (int wall = 0; wall <= 1; wall++) {
                        for (int na0 = 0; na0 < 3; na0++)
                        for (int nb0 = 0; nb0 < target_m; nb0++)
                        for (int na1 = 1; na1 <= 2; na1++)
                        for (int nb1 = 0; nb1 < target_m; nb1++) {
                            Automaton ext = seed.aut;
                            ext.M = target_m;
                            if (wall == 0) ext.b0[from] = new_s;
                            else ext.b1[from] = new_s;
                            ext.a0[new_s] = na0;
                            ext.b0[new_s] = nb0;
                            ext.a1[new_s] = na1;
                            ext.b1[new_s] = nb1;

                            if (try_cand(ext, seed, next_cands)) {
                                fprintf(stderr, "  Beam FOUND M=%d!\n", target_m);
                                goto output;
                            }
                        }
                    }
                }
            }

            // Sort, trim to top-50, but keep all with cov>=395 for full eval
            sort(next_cands.begin(), next_cands.end(),
                 [](const Cand& a, const Cand& b) { return a.cov > b.cov; });
            {
                int keep = 50;
                while (keep < (int)next_cands.size() && next_cands[keep].cov >= 395) keep++;
                if ((int)next_cands.size() > keep) next_cands.resize(keep);
            }

            // Full eval: top-20 always + any with cov>=395
            for (int i = 0; i < (int)next_cands.size() && elapsed() < 1.88; i++) {
                if (i >= 20 && next_cands[i].cov < 395) break;
                auto res = best_start(next_cands[i].aut);
                next_cands[i].cov = res.cov;
                next_cands[i].si = res.si; next_cands[i].sj = res.sj; next_cands[i].sd = res.sd;
                if (res.cov > global_best.cov) global_best = next_cands[i];
                if (res.cov == N*N) {
                    fprintf(stderr, "  Beam top20 FOUND M=%d!\n", target_m);
                    goto output;
                }
            }
            // Re-sort after full eval
            sort(next_cands.begin(), next_cands.end(),
                 [](const Cand& a, const Cand& b) { return a.cov > b.cov; });

            // Merge into seeds for next level
            for (auto& c : next_cands) top_seeds.push_back(c);
            sort(top_seeds.begin(), top_seeds.end(),
                 [](const Cand& a, const Cand& b) { return a.cov > b.cov; });
            if ((int)top_seeds.size() > 80) top_seeds.resize(80);

            fprintf(stderr, "[%.2fs] Beam M=%d: %d cands, best=%d\n",
                    elapsed(), target_m, (int)next_cands.size(),
                    next_cands.empty() ? 0 : next_cands[0].cov);
        }
    }

    // ============================================================
    // Fallback: 全被覆できなかった場合
    //   best partialのロボット + 未カバーセルにspinner (1状態で回転するだけ)
    //   コスト = AK*(K-1) + AM*M_total  (K=1+uncov, M_total=best.M+uncov)
    // ============================================================
    fprintf(stderr, "[%.2fs] No full coverage found (best=%d M=%d). Using fallback.\n",
            elapsed(), global_best.cov, global_best.aut.M);
    {
        // Find exact covered cells of global_best
        bool covered[N][N];
        simulate_cells(global_best.aut, global_best.si, global_best.sj, global_best.sd, covered);

        // Count actually covered
        int cov_cnt = 0;
        for (int i = 0; i < N; i++)
            for (int j = 0; j < N; j++)
                if (covered[i][j]) cov_cnt++;

        // Output: main robot + spinners for uncovered
        int uncov = N*N - cov_cnt;
        int K = 1 + uncov;
        int total_M = global_best.aut.M + uncov;
        long long cost = (long long)ak * (K - 1) + (long long)am * total_M;
        fprintf(stderr, "Fallback: K=%d M_total=%d uncov=%d cost=%lld\n", K, total_M, uncov, cost);

        printf("%d\n", K);
        // Main robot
        printf("%d %d %d %c\n", global_best.aut.M, global_best.si, global_best.sj, DIR_CH[global_best.sd]);
        for (int s = 0; s < global_best.aut.M; s++)
            printf("%s %d %s %d\n",
                ACT_STR[global_best.aut.a0[s]], global_best.aut.b0[s],
                ACT_STR[global_best.aut.a1[s]], global_best.aut.b1[s]);
        // Spinner robots for uncovered cells
        for (int i = 0; i < N; i++)
            for (int j = 0; j < N; j++)
                if (!covered[i][j]) {
                    printf("1 %d %d U\nR 0 R 0\n", i, j);
                }

        // No new walls
        for (int i = 0; i < N; i++) { for (int j = 0; j < N-1; j++) printf("0"); printf("\n"); }
        for (int i = 0; i < N-1; i++) { for (int j = 0; j < N; j++) printf("0"); printf("\n"); }
        return 0;
    }

    output:
    fprintf(stderr, "[%.2fs] Output: M=%d cov=%d start=(%d,%d,%c)\n",
            elapsed(), global_best.aut.M, global_best.cov,
            global_best.si, global_best.sj, DIR_CH[global_best.sd]);

    printf("1\n");
    printf("%d %d %d %c\n", global_best.aut.M, global_best.si, global_best.sj, DIR_CH[global_best.sd]);
    for (int s = 0; s < global_best.aut.M; s++)
        printf("%s %d %s %d\n",
            ACT_STR[global_best.aut.a0[s]], global_best.aut.b0[s],
            ACT_STR[global_best.aut.a1[s]], global_best.aut.b1[s]);
    for (int i = 0; i < N; i++) { for (int j = 0; j < N-1; j++) printf("0"); printf("\n"); }
    for (int i = 0; i < N-1; i++) { for (int j = 0; j < N; j++) printf("0"); printf("\n"); }
    return 0;
}

Submission Info

Submission Time
Task C - Periodic Patrol Automata (C)
User kyuridenamida
Language C++23 (GCC 15.2.0)
Score 2458300788
Code Size 27812 Byte
Status AC
Exec Time 1520 ms
Memory 6140 KiB

Judge Result

Set Name test_ALL
Score / Max Score 2458300788 / 15000000000
Status
AC × 150
Set Name Test Cases
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
Case Name Status Exec Time Memory
test_0000.txt AC 24 ms 3908 KiB
test_0001.txt AC 25 ms 3876 KiB
test_0002.txt AC 1 ms 3888 KiB
test_0003.txt AC 250 ms 3936 KiB
test_0004.txt AC 180 ms 3876 KiB
test_0005.txt AC 181 ms 3836 KiB
test_0006.txt AC 96 ms 3824 KiB
test_0007.txt AC 1520 ms 6064 KiB
test_0008.txt AC 20 ms 3924 KiB
test_0009.txt AC 17 ms 3972 KiB
test_0010.txt AC 44 ms 3764 KiB
test_0011.txt AC 85 ms 3708 KiB
test_0012.txt AC 53 ms 3888 KiB
test_0013.txt AC 189 ms 3764 KiB
test_0014.txt AC 19 ms 3924 KiB
test_0015.txt AC 20 ms 3888 KiB
test_0016.txt AC 134 ms 3972 KiB
test_0017.txt AC 53 ms 3932 KiB
test_0018.txt AC 1 ms 3936 KiB
test_0019.txt AC 53 ms 4028 KiB
test_0020.txt AC 35 ms 3844 KiB
test_0021.txt AC 192 ms 4028 KiB
test_0022.txt AC 1 ms 3868 KiB
test_0023.txt AC 230 ms 3844 KiB
test_0024.txt AC 1 ms 4084 KiB
test_0025.txt AC 177 ms 3824 KiB
test_0026.txt AC 21 ms 3920 KiB
test_0027.txt AC 76 ms 3888 KiB
test_0028.txt AC 206 ms 3836 KiB
test_0029.txt AC 32 ms 3876 KiB
test_0030.txt AC 16 ms 3932 KiB
test_0031.txt AC 21 ms 3936 KiB
test_0032.txt AC 8 ms 3764 KiB
test_0033.txt AC 103 ms 3764 KiB
test_0034.txt AC 62 ms 3888 KiB
test_0035.txt AC 84 ms 3836 KiB
test_0036.txt AC 27 ms 4084 KiB
test_0037.txt AC 1 ms 3876 KiB
test_0038.txt AC 30 ms 3844 KiB
test_0039.txt AC 149 ms 3824 KiB
test_0040.txt AC 22 ms 4084 KiB
test_0041.txt AC 216 ms 3876 KiB
test_0042.txt AC 15 ms 3920 KiB
test_0043.txt AC 312 ms 3876 KiB
test_0044.txt AC 215 ms 4084 KiB
test_0045.txt AC 34 ms 4020 KiB
test_0046.txt AC 110 ms 4084 KiB
test_0047.txt AC 1 ms 4084 KiB
test_0048.txt AC 891 ms 6140 KiB
test_0049.txt AC 101 ms 3932 KiB
test_0050.txt AC 68 ms 3996 KiB
test_0051.txt AC 19 ms 3764 KiB
test_0052.txt AC 297 ms 4028 KiB
test_0053.txt AC 76 ms 3836 KiB
test_0054.txt AC 162 ms 3764 KiB
test_0055.txt AC 227 ms 3844 KiB
test_0056.txt AC 19 ms 3876 KiB
test_0057.txt AC 329 ms 3836 KiB
test_0058.txt AC 69 ms 3888 KiB
test_0059.txt AC 31 ms 3844 KiB
test_0060.txt AC 17 ms 4040 KiB
test_0061.txt AC 1150 ms 6132 KiB
test_0062.txt AC 19 ms 3836 KiB
test_0063.txt AC 41 ms 3824 KiB
test_0064.txt AC 318 ms 3932 KiB
test_0065.txt AC 74 ms 4140 KiB
test_0066.txt AC 186 ms 3708 KiB
test_0067.txt AC 17 ms 4028 KiB
test_0068.txt AC 159 ms 4028 KiB
test_0069.txt AC 19 ms 3876 KiB
test_0070.txt AC 283 ms 4020 KiB
test_0071.txt AC 31 ms 3844 KiB
test_0072.txt AC 1 ms 3932 KiB
test_0073.txt AC 63 ms 3944 KiB
test_0074.txt AC 1 ms 3944 KiB
test_0075.txt AC 1 ms 3844 KiB
test_0076.txt AC 85 ms 3920 KiB
test_0077.txt AC 125 ms 3908 KiB
test_0078.txt AC 1 ms 3944 KiB
test_0079.txt AC 129 ms 3944 KiB
test_0080.txt AC 102 ms 3896 KiB
test_0081.txt AC 135 ms 3764 KiB
test_0082.txt AC 31 ms 3844 KiB
test_0083.txt AC 238 ms 4020 KiB
test_0084.txt AC 1 ms 4028 KiB
test_0085.txt AC 73 ms 4028 KiB
test_0086.txt AC 113 ms 3932 KiB
test_0087.txt AC 44 ms 4084 KiB
test_0088.txt AC 12 ms 3764 KiB
test_0089.txt AC 93 ms 3844 KiB
test_0090.txt AC 26 ms 3876 KiB
test_0091.txt AC 83 ms 3944 KiB
test_0092.txt AC 52 ms 3944 KiB
test_0093.txt AC 46 ms 3836 KiB
test_0094.txt AC 96 ms 3996 KiB
test_0095.txt AC 163 ms 3764 KiB
test_0096.txt AC 114 ms 3816 KiB
test_0097.txt AC 17 ms 3860 KiB
test_0098.txt AC 34 ms 3888 KiB
test_0099.txt AC 77 ms 3908 KiB
test_0100.txt AC 46 ms 4028 KiB
test_0101.txt AC 100 ms 3972 KiB
test_0102.txt AC 78 ms 3844 KiB
test_0103.txt AC 262 ms 3836 KiB
test_0104.txt AC 10 ms 4028 KiB
test_0105.txt AC 1 ms 3936 KiB
test_0106.txt AC 34 ms 3944 KiB
test_0107.txt AC 1 ms 3764 KiB
test_0108.txt AC 48 ms 3944 KiB
test_0109.txt AC 100 ms 3828 KiB
test_0110.txt AC 16 ms 3888 KiB
test_0111.txt AC 213 ms 3904 KiB
test_0112.txt AC 97 ms 3936 KiB
test_0113.txt AC 27 ms 3824 KiB
test_0114.txt AC 1 ms 4028 KiB
test_0115.txt AC 131 ms 3932 KiB
test_0116.txt AC 31 ms 3876 KiB
test_0117.txt AC 124 ms 3944 KiB
test_0118.txt AC 328 ms 3844 KiB
test_0119.txt AC 135 ms 3972 KiB
test_0120.txt AC 265 ms 3920 KiB
test_0121.txt AC 98 ms 3908 KiB
test_0122.txt AC 20 ms 3908 KiB
test_0123.txt AC 13 ms 4040 KiB
test_0124.txt AC 380 ms 3920 KiB
test_0125.txt AC 199 ms 4040 KiB
test_0126.txt AC 119 ms 4028 KiB
test_0127.txt AC 39 ms 4084 KiB
test_0128.txt AC 106 ms 3944 KiB
test_0129.txt AC 135 ms 3908 KiB
test_0130.txt AC 84 ms 3888 KiB
test_0131.txt AC 140 ms 3876 KiB
test_0132.txt AC 109 ms 3764 KiB
test_0133.txt AC 296 ms 3876 KiB
test_0134.txt AC 254 ms 3764 KiB
test_0135.txt AC 134 ms 3924 KiB
test_0136.txt AC 121 ms 4040 KiB
test_0137.txt AC 1 ms 3764 KiB
test_0138.txt AC 32 ms 3932 KiB
test_0139.txt AC 18 ms 3844 KiB
test_0140.txt AC 86 ms 3844 KiB
test_0141.txt AC 18 ms 3888 KiB
test_0142.txt AC 39 ms 3920 KiB
test_0143.txt AC 43 ms 3936 KiB
test_0144.txt AC 230 ms 3888 KiB
test_0145.txt AC 176 ms 3888 KiB
test_0146.txt AC 1 ms 3888 KiB
test_0147.txt AC 332 ms 3876 KiB
test_0148.txt AC 77 ms 3764 KiB
test_0149.txt AC 73 ms 3844 KiB