Submission #33976417


Source Code Expand

#include <cassert>
#include <iostream>
#include <map>
#include <random>
#include <utility>
#include <vector>

using namespace std;


struct MoveAction {
    int before_row, before_col, after_row, after_col;
    MoveAction(int before_row, int before_col, int after_row, int after_col) : 
        before_row(before_row), before_col(before_col), after_row(after_row), after_col(after_col) {}
};

struct ConnectAction {
    int c1_row, c1_col, c2_row, c2_col;
    ConnectAction(int c1_row, int c1_col, int c2_row, int c2_col) : 
        c1_row(c1_row), c1_col(c1_col), c2_row(c2_row), c2_col(c2_col) {}
};

struct Result {
    vector<MoveAction> move;
    vector<ConnectAction> connect;
    Result(const vector<MoveAction> &move, const vector<ConnectAction> &con) : move(move), connect(con) {}
};

struct Solver {
    static constexpr char USED = 'x';
    static constexpr int DR[4] = {0, 1, 0, -1};
    static constexpr int DC[4] = {1, 0, -1, 0};

    int N, K;
    int action_count_limit;
    mt19937 engine;
    vector<string> field;

    Solver(int N, int K, const vector<string> &field, int seed = 0) : 
        N(N), K(K), action_count_limit(K * 100), field(field)
    {
        engine.seed(seed);
    }

    bool can_move(int row, int col, int dir) const
    {
        int nrow = row + DR[dir];
        int ncol = col + DC[dir];
        if (0 <= nrow && nrow < N && 0 <= ncol && ncol < N) {
            return field[nrow][ncol] == '0';
        }
        return false;
    }

    vector<MoveAction> move(int move_limit = -1)
    {
        vector<MoveAction> ret;
        if (move_limit == -1) {
            move_limit = K * 50;
        }

        for (int i = 0; i < move_limit; i++) {
            int row = engine() % N;
            int col = engine() % N;
            int dir = engine() % 4;
            if (field[row][col] != '0' && can_move(row, col, dir)) {
                swap(field[row][col], field[row + DR[dir]][col + DC[dir]]);
                ret.emplace_back(row, col, row + DR[dir], col + DC[dir]);
                action_count_limit--;
            }
        }

        return ret;
    }

    bool can_connect(int row, int col, int dir) const
    {
        int nrow = row + DR[dir];
        int ncol = col + DC[dir];
        while (0 <= nrow && nrow < N && 0 <= ncol && ncol < N) {
            if (field[nrow][ncol] == field[row][col]) {
                return true;
            } else if (field[nrow][ncol] != '0') {
                return false;
            }
            nrow += DR[dir];
            ncol += DC[dir];
        }
        return false;
    }

    ConnectAction line_fill(int row, int col, int dir)
    {
        int nrow = row + DR[dir];
        int ncol = col + DC[dir];
        while (0 <= nrow && nrow < N && 0 <= ncol && ncol < N) {
            if (field[nrow][ncol] == field[row][col]) {
                return ConnectAction(row, col, nrow, ncol);
            }
            assert(field[nrow][ncol] == '0');
            field[nrow][ncol] = USED;
            nrow += DR[dir];
            ncol += DC[dir];
        }
        assert(false);
    }

    vector<ConnectAction> connect()
    {
        vector<ConnectAction> ret;
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < N; j++) {
                if (field[i][j] != '0' && field[i][j] != 'x') {
                    for (int dir = 0; dir < 2; dir++) {
                        if (can_connect(i, j, dir)) {
                            ret.push_back(line_fill(i, j, dir));
                            action_count_limit--;
                            if (action_count_limit <= 0) {
                                return ret;
                            }
                        }
                    }
                }
            }
        }
        return ret;
    }

    Result solve()
    {
        // create random moves
        auto moves = move();
        // from each computer, connect to right and/or bottom if it will reach the same type
        auto connects = connect();
        return Result(moves, connects);
    }
};

struct UnionFind {
    map<pair<int,int>, pair<int, int>> parent;
    UnionFind() :parent() {}

    pair<int, int> find(pair<int, int> x)
    {
        if (parent.find(x) == parent.end()) {
            parent[x] = x;
            return x;
        } else if (parent[x] == x) {
            return x;
        } else {
            parent[x] = find(parent[x]);
            return parent[x];
        }
    }

    void unite(pair<int, int> x, pair<int, int> y)
    {
        x = find(x);
        y = find(y);
        if (x != y) {
            parent[x] = y;
        }
    }
};

int calc_score(int N, vector<string> field, const Result &res)
{
    for (auto r : res.move) {
        assert(field[r.before_row][r.before_col] != '0');
        assert(field[r.after_row][r.after_col] == '0');
        swap(field[r.before_row][r.before_col], field[r.after_row][r.after_col]);
    }

    UnionFind uf;
    for (auto r : res.connect) {
        pair<int, int> p1(r.c1_row, r.c1_col), p2(r.c2_row, r.c2_col);
        uf.unite(p1, p2);
    }

    vector<pair<int, int>> computers;
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < N; j++) {
            if (field[i][j] != '0') {
                computers.emplace_back(i, j);
            }
        }
    }

    int score = 0;
    for (int i = 0; i < (int)computers.size(); i++) {
        for (int j = i+1; j < (int)computers.size(); j++) {
            auto c1 = computers[i];
            auto c2 = computers[j];
            if (uf.find(c1) == uf.find(c2)) {
                score += (field[c1.first][c1.second] == field[c2.first][c2.second]) ? 1 : -1;
            }
        }
    }

    return max(score, 0);
}

void print_answer(const Result &res)
{
    cout << res.move.size() << endl;
    for (auto m : res.move) {
        cout << m.before_row << " " << m.before_col << " "
            << m.after_row << " " << m.after_col << endl;
    }
    cout << res.connect.size() << endl;
    for (auto m : res.connect) {
        cout << m.c1_row << " " << m.c1_col << " "
            << m.c2_row << " " << m.c2_col << endl;
    }
}


int main()
{
    int N, K;
    cin >> N >> K;
    vector<string> field(N);
    for (int i = 0; i < N; i++) {
        cin >> field[i];
    }

    Solver s(N, K, field);
    auto ret = s.solve();

    cerr << "Score = " << calc_score(N, field, ret) << endl;

    print_answer(ret);

    return 0;
}

Submission Info

Submission Time
Task A - Server Room
User NHS93
Language C++ (GCC 9.2.1)
Score 26047
Code Size 6641 Byte
Status AC
Exec Time 41 ms
Memory 3704 KiB

Judge Result

Set Name test_all
Score / Max Score 26047 / 1237500
Status
AC × 50
Set Name Test Cases
test_all subtask_01_01.txt, subtask_01_02.txt, subtask_01_03.txt, subtask_01_04.txt, subtask_01_05.txt, subtask_01_06.txt, subtask_01_07.txt, subtask_01_08.txt, subtask_01_09.txt, subtask_01_10.txt, subtask_01_11.txt, subtask_01_12.txt, subtask_01_13.txt, subtask_01_14.txt, subtask_01_15.txt, subtask_01_16.txt, subtask_01_17.txt, subtask_01_18.txt, subtask_01_19.txt, subtask_01_20.txt, subtask_01_21.txt, subtask_01_22.txt, subtask_01_23.txt, subtask_01_24.txt, subtask_01_25.txt, subtask_01_26.txt, subtask_01_27.txt, subtask_01_28.txt, subtask_01_29.txt, subtask_01_30.txt, subtask_01_31.txt, subtask_01_32.txt, subtask_01_33.txt, subtask_01_34.txt, subtask_01_35.txt, subtask_01_36.txt, subtask_01_37.txt, subtask_01_38.txt, subtask_01_39.txt, subtask_01_40.txt, subtask_01_41.txt, subtask_01_42.txt, subtask_01_43.txt, subtask_01_44.txt, subtask_01_45.txt, subtask_01_46.txt, subtask_01_47.txt, subtask_01_48.txt, subtask_01_49.txt, subtask_01_50.txt
Case Name Status Exec Time Memory
subtask_01_01.txt AC 41 ms 3564 KiB
subtask_01_02.txt AC 36 ms 3656 KiB
subtask_01_03.txt AC 11 ms 3644 KiB
subtask_01_04.txt AC 33 ms 3668 KiB
subtask_01_05.txt AC 17 ms 3492 KiB
subtask_01_06.txt AC 32 ms 3668 KiB
subtask_01_07.txt AC 10 ms 3600 KiB
subtask_01_08.txt AC 32 ms 3652 KiB
subtask_01_09.txt AC 25 ms 3700 KiB
subtask_01_10.txt AC 27 ms 3640 KiB
subtask_01_11.txt AC 9 ms 3492 KiB
subtask_01_12.txt AC 10 ms 3552 KiB
subtask_01_13.txt AC 26 ms 3700 KiB
subtask_01_14.txt AC 32 ms 3664 KiB
subtask_01_15.txt AC 15 ms 3536 KiB
subtask_01_16.txt AC 40 ms 3624 KiB
subtask_01_17.txt AC 39 ms 3508 KiB
subtask_01_18.txt AC 29 ms 3664 KiB
subtask_01_19.txt AC 9 ms 3644 KiB
subtask_01_20.txt AC 12 ms 3616 KiB
subtask_01_21.txt AC 9 ms 3648 KiB
subtask_01_22.txt AC 11 ms 3648 KiB
subtask_01_23.txt AC 23 ms 3680 KiB
subtask_01_24.txt AC 35 ms 3668 KiB
subtask_01_25.txt AC 25 ms 3560 KiB
subtask_01_26.txt AC 24 ms 3640 KiB
subtask_01_27.txt AC 31 ms 3512 KiB
subtask_01_28.txt AC 29 ms 3660 KiB
subtask_01_29.txt AC 39 ms 3568 KiB
subtask_01_30.txt AC 35 ms 3668 KiB
subtask_01_31.txt AC 36 ms 3624 KiB
subtask_01_32.txt AC 34 ms 3564 KiB
subtask_01_33.txt AC 16 ms 3552 KiB
subtask_01_34.txt AC 33 ms 3620 KiB
subtask_01_35.txt AC 35 ms 3704 KiB
subtask_01_36.txt AC 35 ms 3560 KiB
subtask_01_37.txt AC 29 ms 3660 KiB
subtask_01_38.txt AC 38 ms 3552 KiB
subtask_01_39.txt AC 34 ms 3700 KiB
subtask_01_40.txt AC 26 ms 3500 KiB
subtask_01_41.txt AC 10 ms 3604 KiB
subtask_01_42.txt AC 10 ms 3640 KiB
subtask_01_43.txt AC 18 ms 3608 KiB
subtask_01_44.txt AC 16 ms 3564 KiB
subtask_01_45.txt AC 15 ms 3668 KiB
subtask_01_46.txt AC 12 ms 3576 KiB
subtask_01_47.txt AC 27 ms 3668 KiB
subtask_01_48.txt AC 35 ms 3576 KiB
subtask_01_49.txt AC 25 ms 3560 KiB
subtask_01_50.txt AC 30 ms 3688 KiB