Cod sursa(job #3358618)

Utilizator rares89_Dumitriu Rares rares89_ Data 18 iunie 2026 17:05:13
Problema Santa Scor 90
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 6.82 kb
#include <bits/stdc++.h>

using namespace std;

ifstream fin("santa.in");
ofstream fout("santa.out");

int n, m, S, E, Q;
vector<int> adj[45005];
int dfn[45005], low[45005], timer;
stack<pair<int, int>> st;
int num_bcc;
vector<int> bcc_nodes[45005];
vector<int> bct_adj[90005];

int dp_bcc[1 << 16];
int p_bcc[1 << 16][16];

void dfs(int u, int p = 0) {
    dfn[u] = low[u] = ++timer;
    for (int v : adj[u]) {
        if (v == p) continue;
        if (dfn[v]) {
            low[u] = min(low[u], dfn[v]);
            if (dfn[v] < dfn[u]) {
                st.push({u, v});
            }
        } else {
            st.push({u, v});
            dfs(v, u);
            low[u] = min(low[u], low[v]);
            if (low[v] >= dfn[u]) {
                num_bcc++;
                while (true) {
                    auto edge = st.top();
                    st.pop();
                    bcc_nodes[num_bcc].push_back(edge.first);
                    bcc_nodes[num_bcc].push_back(edge.second);
                    if (edge == make_pair(u, v)) break;
                }
                sort(bcc_nodes[num_bcc].begin(), bcc_nodes[num_bcc].end());
                bcc_nodes[num_bcc].erase(unique(bcc_nodes[num_bcc].begin(), bcc_nodes[num_bcc].end()), bcc_nodes[num_bcc].end());
            }
        }
    }
}

bool has_edge(int u, int v) {
    auto it = lower_bound(adj[u].begin(), adj[u].end(), v);
    return it != adj[u].end() && *it == v;
}

vector<int> get_hamiltonian_path(int bcc_idx, int start_node, int end_node) {
    vector<int>& V_bcc = bcc_nodes[bcc_idx];
    int K = V_bcc.size();
    if (K > 16) return {};

    int start_idx = -1, end_idx = -1;
    for (int i = 0; i < K; i++) {
        if (V_bcc[i] == start_node) start_idx = i;
        if (V_bcc[i] == end_node) end_idx = i;
    }

    if (start_idx == -1) return {};
    if (end_node != -1 && end_idx == -1) return {};

    int adj_mask[16] = {0};
    for (int i = 0; i < K; i++) {
        for (int j = 0; j < K; j++) {
            if (i != j && has_edge(V_bcc[i], V_bcc[j])) {
                adj_mask[i] |= (1 << j);
            }
        }
    }

    int max_mask = 1 << K;
    for (int i = 0; i < max_mask; i++) dp_bcc[i] = 0;

    dp_bcc[1 << start_idx] |= (1 << start_idx);

    for (int mask = 0; mask < max_mask; mask++) {
        int valid_u = dp_bcc[mask];
        while (valid_u) {
            int u = __builtin_ctz(valid_u);
            valid_u &= valid_u - 1;

            int available = adj_mask[u] & ~mask;
            while (available) {
                int v = __builtin_ctz(available);
                available &= available - 1;
                
                int next_mask = mask | (1 << v);
                if (!(dp_bcc[next_mask] & (1 << v))) {
                    dp_bcc[next_mask] |= (1 << v);
                    p_bcc[next_mask][v] = u;
                }
            }
        }
    }

    int target_mask = max_mask - 1;
    int last = -1;

    if (end_node != -1) {
        if (dp_bcc[target_mask] & (1 << end_idx)) {
            last = end_idx;
        }
    } else {
        if (dp_bcc[target_mask]) {
            last = __builtin_ctz(dp_bcc[target_mask]);
        }
    }

    if (last == -1) return {};

    vector<int> path;
    int curr_mask = target_mask;
    int curr_node = last;

    while (curr_mask) {
        path.push_back(V_bcc[curr_node]);
        if (curr_mask == (1 << curr_node)) break;
        int prev_node = p_bcc[curr_mask][curr_node];
        curr_mask ^= (1 << curr_node);
        curr_node = prev_node;
    }

    reverse(path.begin(), path.end());
    return path;
}

bool solve_chain(vector<int> bcc_seq, vector<int> cut_seq, vector<int>& final_path) {
    if (bcc_seq.empty()) {
        if (Q == S) {
            final_path = {S};
            return true;
        }
        return false;
    }

    int k = bcc_seq.size();
    int first_bcc = bcc_seq[0] - n; 
    bool q_in_first = false;
    for (int x : bcc_nodes[first_bcc]) {
        if (x == Q) q_in_first = true;
    }
    if (!q_in_first) return false;

    vector<int> path;
    for (int i = 0; i < k; i++) {
        int C_idx = bcc_seq[i] - n;
        int start_node = (i == 0) ? Q : cut_seq[i - 1];
        int end_node = (i == k - 1) ? -1 : cut_seq[i];
        
        vector<int> p = get_hamiltonian_path(C_idx, start_node, end_node);
        if (p.empty()) return false;
        
        if (i == 0) {
            path = p;
        } else {
            for (int j = 1; j < p.size(); j++) {
                path.push_back(p[j]);
            }
        }
    }
    final_path = path;
    return true;
}

int main() {
    fin >> n >> m;
    for (int i = 1; i <= m; i++) {
        int u, v;
        fin >> u >> v;
        adj[u].push_back(v);
        adj[v].push_back(u);
    }
    fin >> S >> E >> Q;

    for (int i = 1; i <= n; i++) {
        sort(adj[i].begin(), adj[i].end());
    }

    for (int i = 1; i <= n; i++) {
        if (!dfn[i]) dfs(i);
    }

    for (int i = 1; i <= num_bcc; i++) {
        for (int u : bcc_nodes[i]) {
            bct_adj[u].push_back(n + i);
            bct_adj[n + i].push_back(u);
        }
    }

    queue<int> q;
    vector<int> bct_parent(n + num_bcc + 1, 0);
    vector<bool> vis(n + num_bcc + 1, false);
    q.push(S);
    vis[S] = true;
    
    while (!q.empty()) {
        int u = q.front();
        q.pop();
        if (u == E) break;
        for (int v : bct_adj[u]) {
            if (!vis[v]) {
                vis[v] = true;
                bct_parent[v] = u;
                q.push(v);
            }
        }
    }

    if (!vis[E] && S != E) {
        fout << "No chance\n";
        return 0;
    }

    vector<int> bct_path;
    int curr = E;
    while (curr != S) {
        bct_path.push_back(curr);
        curr = bct_parent[curr];
    }
    bct_path.push_back(S);
    reverse(bct_path.begin(), bct_path.end());

    vector<int> bcc_seq;
    vector<int> cut_seq;
    for (int i = 0; i < bct_path.size(); i++) {
        if (bct_path[i] > n) {
            bcc_seq.push_back(bct_path[i]);
        } else {
            if (i > 0 && i < bct_path.size() - 1) {
                cut_seq.push_back(bct_path[i]);
            }
        }
    }

    vector<int> final_path;
    if (solve_chain(bcc_seq, cut_seq, final_path)) {
        fout << final_path.size() << "\n";
        for (int x : final_path) fout << x << " ";
        fout << "\n";
        return 0;
    }

    reverse(bcc_seq.begin(), bcc_seq.end());
    reverse(cut_seq.begin(), cut_seq.end());

    if (solve_chain(bcc_seq, cut_seq, final_path)) {
        fout << final_path.size() << "\n";
        for (int x : final_path) fout << x << " ";
        fout << "\n";
        return 0;
    }

    fout << "No chance\n";
    return 0;
}