제출 #1339567

#제출 시각아이디문제언어결과실행 시간메모리
1339567lucas110550세계 지도 (IOI25_worldmap)C++20
100 / 100
487 ms2908 KiB
#include <bits/stdc++.h>
using namespace std;

/* ----------------------------------------------------------------------
   create_map
   ---------------------------------------------------------------------- */
vector<vector<int>> create_map(int N, int M,
                               vector<int> A, vector<int> B)
{
    /* --------------------------------------------------------------
       0‑based adjacency matrix and list of edges
       -------------------------------------------------------------- */
    vector<vector<char>> adj(N, vector<char>(N, 0));
    vector<pair<int,int>> edges;
    edges.reserve(M);

    for (int k = 0; k < M; ++k) {
        int u = A[k] - 1;                 // to 0‑based
        int v = B[k] - 1;
        adj[u][v] = adj[v][u] = 1;
        edges.emplace_back(u, v);
    }
    const int M_edges = static_cast<int>(edges.size());

    /* --------------------------------------------------------------
       edge_id[u][v]  (only for u < v)  →  index of the edge in `edges`
       -------------------------------------------------------------- */
    vector<vector<int>> edge_id(N, vector<int>(N, -1));
    for (int idx = 0; idx < M_edges; ++idx) {
        int u = edges[idx].first;
        int v = edges[idx].second;
        if (u > v) swap(u, v);
        edge_id[u][v] = idx;
    }

    /* --------------------------------------------------------------
       neighbour_mask[i] – bit mask of colours that may be placed
       next to a cell whose colour is i (loops + the 4‑neighbours)
       -------------------------------------------------------------- */
    vector<uint64_t> neighbour_mask(N, 0);
    for (int i = 0; i < N; ++i) {
        uint64_t mask = 1ULL << i;                // the colour itself
        for (int j = 0; j < N; ++j)
            if (adj[i][j]) mask |= (1ULL << j);
        neighbour_mask[i] = mask;
    }
    const uint64_t all_mask = (N == 64) ? ~0ULL : ((1ULL << N) - 1ULL);

    /* --------------------------------------------------------------
       board size K (smallest board that could possibly work)
       -------------------------------------------------------------- */
    int K0 = static_cast<int>(sqrt((double)N));
    while (K0 * K0 < N) ++K0;                     // ceil(sqrt(N))

    int Kedge = 0;
    while (2 * Kedge * (Kedge - 1) < M_edges) ++Kedge;

    int K = max(K0, Kedge);
    K = max(K, 2 * N);                            // a bit of spare space
    if (K > 240) K = 240;                         // safety cap

    /* --------------------------------------------------------------
       random generator – used for the “several random attempts”
       -------------------------------------------------------------- */
    std::mt19937 rng(
        static_cast<unsigned>(chrono::steady_clock::now()
                                 .time_since_epoch()
                                 .count()));

    const int MAX_ATTEMPTS = 500;

    for (int attempt = 0; attempt < MAX_ATTEMPTS; ++attempt) {
        /* ----- fresh board for this attempt ---------------------- */
        vector<vector<int>> grid(K, vector<int>(K, -1));
        uint64_t used_colours = 0;                // bit mask of colours already used
        vector<char> covered(M_edges, 0);
        int covered_cnt = 0;
        bool ok = true;

        /* ----- greedy filling of the K×K board ------------------- */
        for (int i = 0; i < K && ok; ++i) {
            for (int j = 0; j < K; ++j) {
                uint64_t allowed = all_mask;      // colours allowed by neighbours

                if (i > 0) {
                    int top = grid[i-1][j];
                    allowed &= neighbour_mask[top];
                }
                if (j > 0) {
                    int left = grid[i][j-1];
                    allowed &= neighbour_mask[left];
                }

                if (allowed == 0) {               // dead end → restart whole board
                    ok = false;
                    break;
                }

                uint64_t missing = all_mask & ~used_colours;
                uint64_t missing_allowed = allowed & missing;

                /* ----- pick the colour with the best gain ---------- */
                int best_gain = -1;
                vector<int> candidates;

                uint64_t mask = allowed;
                while (mask) {
                    uint64_t lsb = mask & -mask;
                    int c = __builtin_ctzll(lsb);   // colour index (0‑based)
                    mask ^= lsb;

                    int gain = 0;

                    /* edges that would become covered if we use colour c */
                    if (i > 0) {
                        int nt = grid[i-1][j];
                        if (nt != c && adj[nt][c]) {
                            int u = min(nt, c), v = max(nt, c);
                            int eid = edge_id[u][v];
                            if (eid != -1 && !covered[eid]) ++gain;
                        }
                    }
                    if (j > 0) {
                        int nl = grid[i][j-1];
                        if (nl != c && adj[nl][c]) {
                            int u = min(nl, c), v = max(nl, c);
                            int eid = edge_id[u][v];
                            if (eid != -1 && !covered[eid]) ++gain;
                        }
                    }

                    /* huge bonus for a colour that has never been used */
                    if (missing_allowed && ( (1ULL << c) & missing_allowed ))
                        gain += 1000;

                    if (gain > best_gain) {
                        best_gain = gain;
                        candidates.clear();
                        candidates.push_back(c);
                    } else if (gain == best_gain) {
                        candidates.push_back(c);
                    }
                }   // end while(mask)

                /* ----- random tie‑break among the best candidates --- */
                uniform_int_distribution<int> dist(0, (int)candidates.size() - 1);
                int chosen = candidates[dist(rng)];

                /* ----- store the colour -------------------------------- */
                grid[i][j] = chosen;
                used_colours |= (1ULL << chosen);

                /* ----- mark newly created edges ------------------------ */
                if (i > 0) {
                    int nt = grid[i-1][j];
                    if (nt != chosen && adj[nt][chosen]) {
                        int u = min(nt, chosen), v = max(nt, chosen);
                        int eid = edge_id[u][v];
                        if (eid != -1 && !covered[eid]) {
                            covered[eid] = 1;
                            ++covered_cnt;
                        }
                    }
                }
                if (j > 0) {
                    int nl = grid[i][j-1];
                    if (nl != chosen && adj[nl][chosen]) {
                        int u = min(nl, chosen), v = max(nl, chosen);
                        int eid = edge_id[u][v];
                        if (eid != -1 && !covered[eid]) {
                            covered[eid] = 1;
                            ++covered_cnt;
                        }
                    }
                }
            }   // end for j
        }       // end for i

        if (!ok) continue;
        if (used_colours != all_mask) continue;        // not all colours used
        if (covered_cnt != M_edges) continue;          // some edges still uncovered

        /* ----- SUCCESS – convert to 1‑based output ---------------- */
        vector<vector<int>> answer(K, vector<int>(K));
        for (int i = 0; i < K; ++i)
            for (int j = 0; j < K; ++j)
                answer[i][j] = grid[i][j] + 1;          // back to 1‑based
        return answer;
    }   // end for attempts

    /* --------------------------------------------------------------
       Very unlikely fallback – deterministic construction
       -------------------------------------------------------------- */
    int Kfallback = max(2 * N, 2);
    Kfallback = min(Kfallback, 240);
    vector<vector<int>> grid(Kfallback, vector<int>(Kfallback, 1));
    int limit = min(N, Kfallback);
    for (int i = 0; i < limit; ++i)
        grid[i][i] = i + 1;                     // put distinct colours on the diagonal

    return grid;
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...