제출 #1329839

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

static inline long long edge_key(int u, int v) {
    if (u > v) std::swap(u, v);
    return (static_cast<long long>(u) << 32) | static_cast<unsigned int>(v);
}

std::vector<std::vector<int>> create_map(int N, int M,
                                        std::vector<int> A,
                                        std::vector<int> B) {
    // adjacency list + neighbor sets
    std::vector<std::unordered_set<int>> neighbors(N + 1);
    std::vector<std::vector<int>> adj(N + 1);
    neighbors.reserve(N + 1);
    adj.reserve(N + 1);

    for (int i = 0; i < M; i++) {
        int u = A[i], v = B[i];
        neighbors[u].insert(v);
        neighbors[v].insert(u);
        adj[u].push_back(v);
        adj[v].push_back(u);
    }

    // Build a spanning tree walk (Euler tour sequence) via DFS
    std::vector<char> visited(N + 1, 0);
    std::vector<int> seq;
    seq.reserve(2 * N + 5);

    std::function<void(int)> dfs = [&](int u) {
        visited[u] = 1;
        seq.push_back(u);
        for (int v : adj[u]) {
            if (!visited[v]) {
                dfs(v);
                seq.push_back(u);
            }
        }
    };

    int start = 1;
    dfs(start);

    // Append any missing vertices (if disconnected)
    {
        std::vector<char> in_seq(N + 1, 0);
        for (int x : seq) in_seq[x] = 1;
        for (int v = 1; v <= N; v++) {
            if (!in_seq[v]) seq.push_back(v);
        }
    }

    int K = (int)seq.size();
    std::vector<int> row0 = seq;

    // needed edges
    std::unordered_set<long long> needed_edges;
    needed_edges.reserve((size_t)M * 2 + 10);
    for (int i = 0; i < M; i++) {
        needed_edges.insert(edge_key(A[i], B[i]));
    }

    std::vector<int> vertices;
    vertices.reserve(N);
    for (int v = 1; v <= N; v++) vertices.push_back(v);

    // RNG
    std::mt19937 rng((uint32_t)std::chrono::high_resolution_clock::now().time_since_epoch().count());

    int max_attempts = 300;
    for (int attempt = 0; attempt < max_attempts; attempt++) {
        std::vector<std::vector<int>> rows;
        rows.reserve(K);
        rows.push_back(row0);

        bool ok = true;

        for (int i = 1; i < K; i++) {
            std::vector<int> row(K, 0);
            bool row_ok = true;

            for (int j = 0; j < K; j++) {
                int above = rows[i - 1][j];
                int left = (j > 0 ? row[j - 1] : -1);

                const auto& neigh_above = neighbors[above];
                const std::unordered_set<int>* neigh_left = (left != -1 ? &neighbors[left] : nullptr);

                std::vector<int> cand;
                cand.reserve(N);

                for (int c : vertices) {
                    // vertical condition
                    if (above != c && neigh_above.find(c) == neigh_above.end()) continue;
                    // horizontal condition
                    if (left != -1) {
                        if (left != c && neigh_left->find(c) == neigh_left->end()) continue;
                    }
                    cand.push_back(c);
                }

                if (cand.empty()) {
                    row_ok = false;
                    break;
                }

                std::uniform_int_distribution<int> dist(0, (int)cand.size() - 1);
                row[j] = cand[dist(rng)];
            }

            if (!row_ok) {
                ok = false;
                break;
            }
            rows.push_back(std::move(row));
        }

        if (!ok) continue;

        // verify every colour appears at least once
        std::vector<char> present(N + 1, 0);
        int cnt_present = 0;
        for (const auto& r : rows) {
            for (int x : r) {
                if (!present[x]) {
                    present[x] = 1;
                    cnt_present++;
                }
            }
        }
        if (cnt_present < N) continue;

        // compute edges that appear in the grid
        std::unordered_set<long long> edge_set;
        edge_set.reserve((size_t)K * (size_t)K * 2 + 10);

        for (int i = 0; i < K; i++) {
            for (int j = 0; j + 1 < K; j++) {
                int u = rows[i][j], v = rows[i][j + 1];
                if (u != v) edge_set.insert(edge_key(u, v));
            }
        }
        for (int i = 0; i + 1 < K; i++) {
            for (int j = 0; j < K; j++) {
                int u = rows[i][j], v = rows[i + 1][j];
                if (u != v) edge_set.insert(edge_key(u, v));
            }
        }

        // check subset
        bool subset_ok = true;
        for (auto key : needed_edges) {
            if (edge_set.find(key) == edge_set.end()) {
                subset_ok = false;
                break;
            }
        }

        if (subset_ok) return rows;
    }

    // Fallback deterministic construction
    K = std::max(N, 2 * (int)std::sqrt(2.0 * M) + 1);
    if (K % 2 == 1) K += 1;
    K = std::min(K, 240);

    int block_w = 2;
    int blocks_per_row = K / block_w;

    std::vector<std::vector<int>> grid(K, std::vector<int>(K, 1));
    for (int idx = 0; idx < M; idx++) {
        int r = idx / blocks_per_row;
        int c = (idx % blocks_per_row) * block_w;
        if (r >= K || c + 1 >= K) break; // safety
        grid[r][c] = A[idx];
        grid[r][c + 1] = B[idx];
    }
    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...