제출 #1351773

#제출 시각아이디문제언어결과실행 시간메모리
1351773tickcrossy세계 지도 (IOI25_worldmap)C++20
22 / 100
1095 ms4736 KiB
#include <vector>
#include <queue>
#include <algorithm>
#include <cmath>
#include <random>
#include <chrono>
#include <cstring>
#include <set>

using namespace std;

struct SASolver {
    int N, K_SA;
    int is_edge[45][45];
    int adj_count[45][45];
    int color_count[45];
    int color_cells_r[45][6400];
    int color_cells_c[45][6400];
    int color_cells_sz[45];
    int cell_pos[85][85];
    int missing_edge_u[1000];
    int missing_edge_v[1000];
    int missing_edge_pos[45][45];
    int missing_edge_sz;
    int invalid_pairs;
    int missing_colors;
    int C_grid[85][85];

    void add_missing(int u, int v) {
        if(u > v) swap(u, v);
        missing_edge_u[missing_edge_sz] = u;
        missing_edge_v[missing_edge_sz] = v;
        missing_edge_pos[u][v] = missing_edge_sz;
        missing_edge_sz++;
    }

    void remove_missing(int u, int v) {
        if(u > v) swap(u, v);
        int pos = missing_edge_pos[u][v];
        int last_u = missing_edge_u[missing_edge_sz - 1];
        int last_v = missing_edge_v[missing_edge_sz - 1];
        missing_edge_u[pos] = last_u;
        missing_edge_v[pos] = last_v;
        missing_edge_pos[last_u][last_v] = pos;
        missing_edge_sz--;
    }

    void add_adj(int u, int v, int delta) {
        if(u == v) return;
        if(u > v) swap(u, v);
        int old_c = adj_count[u][v];
        adj_count[u][v] += delta;
        int new_c = adj_count[u][v];
        
        if(is_edge[u][v]) {
            if(old_c == 0 && new_c > 0) remove_missing(u, v);
            if(old_c > 0 && new_c == 0) add_missing(u, v);
        } else {
            if(old_c == 0 && new_c > 0) invalid_pairs++;
            if(old_c > 0 && new_c == 0) invalid_pairs--;
        }
    }

    void add_color(int u, int delta) {
        int old_c = color_count[u];
        color_count[u] += delta;
        int new_c = color_count[u];
        if(old_c == 0 && new_c > 0) missing_colors--;
        if(old_c > 0 && new_c == 0) missing_colors++;
    }

    void change_color(int r, int c, int new_col) {
        int old_col = C_grid[r][c];
        if(old_col == new_col) return;
        
        if(r > 0) add_adj(old_col, C_grid[r-1][c], -1);
        if(r < K_SA - 1) add_adj(old_col, C_grid[r+1][c], -1);
        if(c > 0) add_adj(old_col, C_grid[r][c-1], -1);
        if(c < K_SA - 1) add_adj(old_col, C_grid[r][c+1], -1);
        
        C_grid[r][c] = new_col;
        
        if(r > 0) add_adj(new_col, C_grid[r-1][c], 1);
        if(r < K_SA - 1) add_adj(new_col, C_grid[r+1][c], 1);
        if(c > 0) add_adj(new_col, C_grid[r][c-1], 1);
        if(c < K_SA - 1) add_adj(new_col, C_grid[r][c+1], 1);
        
        add_color(old_col, -1);
        add_color(new_col, 1);
        
        int pos = cell_pos[r][c];
        int last_r = color_cells_r[old_col][color_cells_sz[old_col] - 1];
        int last_c = color_cells_c[old_col][color_cells_sz[old_col] - 1];
        
        color_cells_r[old_col][pos] = last_r;
        color_cells_c[old_col][pos] = last_c;
        cell_pos[last_r][last_c] = pos;
        color_cells_sz[old_col]--;
        
        int new_pos = color_cells_sz[new_col]++;
        color_cells_r[new_col][new_pos] = r;
        color_cells_c[new_col][new_pos] = c;
        cell_pos[r][c] = new_pos;
    }

    void init(int n, int k, const vector<vector<int>>& initial_C, const vector<vector<int>>& adj_mat) {
        N = n; K_SA = k;
        invalid_pairs = 0; missing_colors = 0; missing_edge_sz = 0;
        
        memset(is_edge, 0, sizeof(is_edge));
        memset(adj_count, 0, sizeof(adj_count));
        memset(color_count, 0, sizeof(color_count));
        memset(color_cells_sz, 0, sizeof(color_cells_sz));
        
        for(int i=1; i<=N; ++i) {
            for(int j=1; j<=N; ++j) is_edge[i][j] = adj_mat[i][j];
        }
        
        for(int i=1; i<=N; ++i) {
            for(int j=i+1; j<=N; ++j) if(is_edge[i][j]) add_missing(i, j);
        }
        missing_colors = N; 
        
        for(int i=0; i<K_SA; ++i) {
            for(int j=0; j<K_SA; ++j) {
                C_grid[i][j] = initial_C[i][j];
                int c_val = C_grid[i][j];
                int pos = color_cells_sz[c_val]++;
                color_cells_r[c_val][pos] = i; color_cells_c[c_val][pos] = j;
                cell_pos[i][j] = pos;
                if(color_count[c_val] == 0) missing_colors--;
                color_count[c_val]++;
            }
        }
        
        for(int i=0; i<K_SA; ++i) {
            for(int j=0; j<K_SA; ++j) {
                int c_val = C_grid[i][j];
                if(i < K_SA - 1) {
                    int c2 = C_grid[i+1][j];
                    if(c_val != c2) {
                        int u = c_val, v = c2; if(u > v) swap(u, v);
                        int old_a = adj_count[u][v]++;
                        if(is_edge[u][v]) { if(old_a == 0) remove_missing(u, v); } 
                        else { if(old_a == 0) invalid_pairs++; }
                    }
                }
                if(j < K_SA - 1) {
                    int c2 = C_grid[i][j+1];
                    if(c_val != c2) {
                        int u = c_val, v = c2; if(u > v) swap(u, v);
                        int old_a = adj_count[u][v]++;
                        if(is_edge[u][v]) { if(old_a == 0) remove_missing(u, v); } 
                        else { if(old_a == 0) invalid_pairs++; }
                    }
                }
            }
        }
    }

    bool solve(mt19937& rng) {
        double temp = 50.0;
        double cooling_rate = 0.99995;
        
        for(int iter = 0; iter < 150000; ++iter) {
            if(invalid_pairs == 0 && missing_edge_sz == 0 && missing_colors == 0) return true;
            
            int r, c, new_col;
            if(missing_edge_sz > 0 && (rng() % 2 == 0)) {
                int e_idx = rng() % missing_edge_sz;
                int u = missing_edge_u[e_idx], v = missing_edge_v[e_idx];
                if(rng() % 2) swap(u, v);
                
                if(color_cells_sz[u] > 0) {
                    int cell_idx = rng() % color_cells_sz[u];
                    r = color_cells_r[u][cell_idx]; c = color_cells_c[u][cell_idx];
                    int dr[] = {-1, 1, 0, 0}, dc[] = {0, 0, -1, 1};
                    int dir = rng() % 4; r += dr[dir]; c += dc[dir];
                    if(r < 0 || r >= K_SA || c < 0 || c >= K_SA) continue;
                    new_col = v;
                } else { r = rng() % K_SA; c = rng() % K_SA; new_col = (rng() % N) + 1; }
            } else { r = rng() % K_SA; c = rng() % K_SA; new_col = (rng() % N) + 1; }
            
            int old_col = C_grid[r][c];
            if(old_col == new_col) continue;
            
            int old_E = invalid_pairs * 100 + missing_edge_sz * 10 + missing_colors * 1000;
            change_color(r, c, new_col);
            int new_E = invalid_pairs * 100 + missing_edge_sz * 10 + missing_colors * 1000;
            
            if(new_E > old_E) {
                double prob = exp((old_E - new_E) / temp);
                if((rng() % 1000000) / 1000000.0 >= prob) change_color(r, c, old_col);
            }
            temp *= cooling_rate;
        }
        return (invalid_pairs == 0 && missing_edge_sz == 0 && missing_colors == 0);
    }
};

vector<vector<int>> create_map(int N, int M, vector<int> A, vector<int> B) {
    if (N == 1) return {{1}};
    
    vector<vector<int>> adj_matrix(N + 1, vector<int>(N + 1, 0));
    vector<vector<int>> adj(N + 1);
    for (int i = 0; i < M; ++i) {
        adj[A[i]].push_back(B[i]); adj[B[i]].push_back(A[i]);
        adj_matrix[A[i]][B[i]] = 1; adj_matrix[B[i]][A[i]] = 1;
    }

    // Algorithm 1: Eulerian Path max Matrix (Perfect for sparse)
    vector<vector<int>> dist(N + 1, vector<int>(N + 1, 1e9));
    vector<vector<int>> nxt_node(N + 1, vector<int>(N + 1, 0));
    for (int i = 1; i <= N; ++i) {
        dist[i][i] = 0; queue<int> q; q.push(i);
        while (!q.empty()) {
            int u = q.front(); q.pop();
            for (int v : adj[u]) {
                if (dist[i][v] > dist[i][u] + 1) {
                    dist[i][v] = dist[i][u] + 1;
                    nxt_node[i][v] = (u == i) ? v : nxt_node[i][u];
                    q.push(v);
                }
            }
        }
    }
    
    vector<int> odd_nodes;
    for (int i = 1; i <= N; ++i) if (adj[i].size() % 2 != 0) odd_nodes.push_back(i);

    mt19937 rng(1337);
    int min_added = 1e9;
    vector<pair<int, int>> best_added;
    for (int iter = 0; iter < 50; ++iter) {
        vector<int> cur_odd = odd_nodes;
        shuffle(cur_odd.begin(), cur_odd.end(), rng);
        vector<bool> m(cur_odd.size(), false);
        vector<pair<int, int>> cur_added;
        int cur_dist = 0;
        for (int i = 0; i < cur_odd.size(); ++i) {
            if (m[i]) continue;
            int best_j = -1, best_d = 1e9;
            for (int j = i + 1; j < cur_odd.size(); ++j) {
                if (!m[j] && dist[cur_odd[i]][cur_odd[j]] < best_d) {
                    best_d = dist[cur_odd[i]][cur_odd[j]]; best_j = j;
                }
            }
            if (best_j != -1) {
                m[i] = m[best_j] = true; cur_dist += best_d;
                int curr = cur_odd[i], target = cur_odd[best_j];
                while (curr != target) {
                    int nex = nxt_node[curr][target];
                    cur_added.push_back({curr, nex}); curr = nex;
                }
            }
        }
        if (cur_dist < min_added) { min_added = cur_dist; best_added = cur_added; }
    }

    vector<pair<int, int>> euler_edges;
    for (int i = 0; i < M; ++i) euler_edges.push_back({A[i], B[i]});
    euler_edges.insert(euler_edges.end(), best_added.begin(), best_added.end());

    vector<multiset<int>> euler_adj(N + 1);
    for (auto e : euler_edges) { euler_adj[e.first].insert(e.second); euler_adj[e.second].insert(e.first); }

    vector<int> circuit;
    auto dfs_euler = [&](auto& self, int u) -> void {
        while (!euler_adj[u].empty()) {
            int v = *euler_adj[u].begin();
            euler_adj[u].erase(euler_adj[u].begin()); euler_adj[v].erase(euler_adj[v].find(u));
            self(self, v);
        }
        circuit.push_back(u);
    };
    dfs_euler(dfs_euler, 1);

    if (circuit.size() <= 2 * N) {
        int K = circuit.size();
        vector<vector<int>> best_C(K, vector<int>(K));
        for (int i = 0; i < K; ++i) {
            for (int j = 0; j < K; ++j) best_C[i][j] = circuit[max(i, j)];
        }
        return best_C;
    }

    // Algorithm 2: Initial LCA Tree Spanning Sequence + Simulated Annealing (Perfect for Dense)
    SASolver solver;
    auto start_time = chrono::steady_clock::now();
    
    while(true) {
        auto now = chrono::steady_clock::now();
        if(chrono::duration_cast<chrono::milliseconds>(now - start_time).count() > 30) break;
        
        int root = (rng() % N) + 1;
        vector<vector<int>> tree_adj(N + 1);
        vector<bool> vis(N + 1, false);
        queue<int> q; q.push(root); vis[root] = true;
        while(!q.empty()){
            int u = q.front(); q.pop();
            vector<int> neighbors = adj[u]; shuffle(neighbors.begin(), neighbors.end(), rng);
            for(int v : neighbors) {
                if(!vis[v]) {
                    vis[v] = true;
                    tree_adj[u].push_back(v); tree_adj[v].push_back(u);
                    q.push(v);
                }
            }
        }
        
        vector<int> depth(N + 1, 0), parent_node(N + 1, 0), E_base;
        auto dfs_tour = [&](auto& self, int u, int p, int d) -> void {
            depth[u] = d; parent_node[u] = p; E_base.push_back(u);
            for(int v : tree_adj[u]) { if(v != p){ self(self, v, u, d+1); E_base.push_back(u); } }
        };
        dfs_tour(dfs_tour, root, 0, 0);

        auto get_lca = [&](int u, int v) -> int {
            while(depth[u] > depth[v]) u = parent_node[u];
            while(depth[v] > depth[u]) v = parent_node[v];
            while(u != v){ u = parent_node[u]; v = parent_node[v]; }
            return u;
        };

        int K_SA = E_base.size();
        vector<vector<int>> initial_C(K_SA, vector<int>(K_SA));
        for(int i=0; i<K_SA; ++i) {
            for(int j=0; j<K_SA; ++j) initial_C[i][j] = get_lca(E_base[i], E_base[j]);
        }
        
        solver.init(N, K_SA, initial_C, adj_matrix);
        bool success = solver.solve(rng);
        
        if (success) {
            vector<vector<int>> best_C(K_SA, vector<int>(K_SA));
            for(int i=0; i<K_SA; ++i) {
                for(int j=0; j<K_SA; ++j) best_C[i][j] = solver.C_grid[i][j];
            }
            return best_C;
        }
    }

    // Base fallback safety measure 
    int K = circuit.size();
    if (K > 240) return {{1}}; 
    vector<vector<int>> best_C(K, vector<int>(K));
    for (int i = 0; i < K; ++i) {
        for (int j = 0; j < K; ++j) best_C[i][j] = circuit[max(i, j)];
    }
    return best_C;
}
#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...