Cod sursa(job #3348541)

Utilizator TomMMMMatei Toma TomMMM Data 22 martie 2026 15:39:40
Problema Santa Scor 60
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 7.51 kb
#include <fstream>
#include <vector>
#include <stack>
#include <bitset>
#include <queue>

using namespace std;

typedef vector<int> vint;
typedef vector<vint> graph;

void reverse(vint& v){
    for(int i = 0, j = v.size() - 1; i < j; i++, j--)
        swap(v[i], v[j]);
}
void pop_first(vint &path){
    for(int i = 1; i < path.size(); i++)
        path[i - 1] = path[i];
    path.pop_back();
}

const int N_MAX = 45005;
const int TREE_MAX = 2 * N_MAX;
const int SIGMA = 16;

const int ALR_DONE = -2;
const int IMPOSSIBLE = -1;

int n;
graph G;
int elf, santa;
int gica_place;

void read_graph(){
    ifstream fin("santa.in");
    int m;
    fin >> n >> m;
    G.resize(n + 1);
    
    while(m--){
        int x, y;
        fin >> x >> y;
        G[x].push_back(y);
        G[y].push_back(x);
    }

    fin >> elf >> santa >> gica_place;
    fin.close();
}

int in[N_MAX], lwk[N_MAX];
int stack_[N_MAX], vf;
inline int top(){
    return stack_[vf - 1];
}

vint comp_bicon[N_MAX];
int cnt_bicon;

int art_point[N_MAX], cnt_art_points;
int comp_of_node[N_MAX];
vint node_to_art;

graph tree;
bitset<TREE_MAX> seen, allowed;

void create_comp(int node, int son){
    cnt_bicon++;
    while(top() != son){ // a little trick 
        comp_bicon[cnt_bicon].push_back(top());
        comp_of_node[top()] = cnt_bicon;
        vf--;
    }
    comp_bicon[cnt_bicon].push_back(top());
    comp_of_node[top()] = cnt_bicon;
    vf--;
    comp_bicon[cnt_bicon].push_back(node);
    comp_of_node[node] = cnt_bicon;
}

void dfs_bicon(int node, int parent){
    static int global_time = 0;
    in[node] = lwk[node] = ++global_time;
    stack_[vf++] = node;

    int sons_bicon = 0;

    for(int& son: G[node]){
        if(parent == son) continue;
        if(in[son]) lwk[node] = min(lwk[node], in[son]);
        else{ // hasn't been discovered
            dfs_bicon(son, node);
            lwk[node] = min(lwk[node], lwk[son]);
            if(in[node] <= lwk[son]){ // node is articulation point
                sons_bicon++;
                create_comp(node, son);
            }
        }
    }
    if(sons_bicon >= 2 || (sons_bicon == 1 && parent))
        art_point[node] = ++cnt_art_points;
}

void compute_tree_bicon(){
    dfs_bicon(1, 0); // breaking into biconected components

    // transforming them into nodes
    node_to_art.resize(cnt_art_points + 1);
    
    for(int i = 1; i <= n; i++){
        if(art_point[i]){
            node_to_art[art_point[i]] = i;
            art_point[i] += cnt_bicon;
        }
    }
    
    tree.resize(cnt_bicon + cnt_art_points + 1);
    for(int i = 1; i <= cnt_bicon; i++){
        for(const int& u: comp_bicon[i]){
            if(!art_point[u]) continue;
            tree[i].push_back(art_point[u]);
            tree[art_point[u]].push_back(i);
        }
    }
}

inline int graph_to_tree(int x){
    return (art_point[x]? 
        art_point[x]:
        comp_of_node[x]
    ); 
}

int elf_tree, santa_tree;
vint tree_path, depth, 
    final_path, ant;

bool dfs_path(int u){
    if(u == santa_tree) return 1; 
    seen[u] = 1;
    for(const int& v: tree[u]){
        if(!seen[v] && dfs_path(v)){
            tree_path.push_back(v);
            return 1;
        }
    }
    return 0;
}
void dfs_depth(int u){
    for(const int&v: tree[u]){
        if(!depth[v]){
            depth[v] = depth[u] + 1;
            dfs_depth(v);
        }
    }
}

queue<int> que;
int append_shortest_path(int tree_node){
    // this function will print the sp from gica_place to any node
    // that coresponds to the tree_node while printing the last node
    // in the path if the last node is an articulation point

    depth.resize(n + 1, 0); ant.resize(n + 1, 0);
    for(int i = 1; i <= n; i++) depth[i] = 0;
    
    depth[gica_place] = 1;
    que.push(gica_place);
    while(!que.empty()){
        int u = que.front(); 
        que.pop();
        for(const int& v: G[u]){
            if(!depth[v]){
                depth[v] = 1 + depth[u];
                ant[v] = u;
                que.push(v);
            }
        }
    }
    
    int mark;
    if(tree_node > cnt_bicon) mark = node_to_art[tree_node - cnt_bicon];
    else{
        mark = comp_bicon[tree_node][0];
        for(int u: comp_bicon[tree_node])
            if(depth[mark] > depth[u]) mark = u;
    }
    depth[0] = ant[gica_place] = 0;
    while(depth[mark]){
        final_path.push_back(mark);
        mark = ant[mark];
    }
    reverse(final_path);
    return final_path.back();
}

int first_test(){
    santa_tree = graph_to_tree(santa);
    elf_tree = graph_to_tree(elf);
    int gica_tree = graph_to_tree(gica_place);
    
    
    dfs_path(elf_tree);
    tree_path.push_back(elf_tree);

    if(tree_path.size() == 1 && tree_path[0] > cnt_bicon){
        // elf and santa colide and form an art point
        append_shortest_path(tree_path[0]);
        return ALR_DONE;
    }

    depth.resize(cnt_art_points + cnt_bicon + 1);
    depth[gica_tree] = 1;
    dfs_depth(gica_tree);

    int nearest_node = santa_tree;
    for(int u: tree_path)
        if(depth[nearest_node] > depth[u])
            nearest_node = u;

    // first node in the list was an articulation point
    if(tree_path[0] > cnt_bicon) pop_first(tree_path);
    
    // the last node in the list was an articulation point 
    if(tree_path.back() > cnt_bicon) tree_path.pop_back();
        
    if(nearest_node != tree_path[0] && nearest_node != tree_path.back()) 
        return IMPOSSIBLE;

    // the path array is reversed from when it has been built
    
    if(tree_path.back() == nearest_node) reverse(tree_path);
    return append_shortest_path(tree_path[0]);
}

void output_imp(){
    ofstream fout("santa.out");
    fout << "No chance";
    fout.close();
}
void output_final_path(){
    ofstream fout("santa.out");
    fout << final_path.size() << '\n';
    for(int x: final_path)
        fout << x << ' ';
    fout.close();
}

int len, ending, hem_chain[SIGMA];
int generated_chain[SIGMA];
bool found_chain;

void back_tr(int k){
    if(k == len){
        if(ending == -1 || hem_chain[len - 1] == ending){
            found_chain = 1;
            for(int i = 0; i < len; i++)
                generated_chain[i] = hem_chain[i];
        }
        return;
    }
    for(int v: G[hem_chain[k - 1]]){
        if(found_chain || !allowed[v] || seen[v]) continue;
        hem_chain[k] = v;
        seen[v] = 1;
        back_tr(k + 1);
        seen[v] = 0;
    }
}

bool append_hem_cycle(int bc, int start, int end){
    len = comp_bicon[bc].size(); ending = end;
    for(int u: comp_bicon[bc]) allowed[u] = 1;
    
    hem_chain[0] = start;
    seen[start] = 1;
    found_chain = 0;
    
    back_tr(1);
    for(int u: comp_bicon[bc]) allowed[u] = 0;

    if(found_chain == 0) return 0;

    for(int i = 1; i < len; i++) // ignore the first one cuz it would be added twice
        final_path.push_back(generated_chain[i]);
    return 1;
}

int main(){
    read_graph();
    compute_tree_bicon();
    

    int head = first_test();
    if(head == IMPOSSIBLE){
        output_imp();
        return 0;
    }

    if(head == ALR_DONE){
        output_final_path();
        return 0;
    }

    bool still_possible = 1;
    seen.reset();

    for(int i = 0; i < (int)tree_path.size() && still_possible; i++){
        if(tree_path[i] > cnt_bicon) continue;
        int tail = (i + 1 < (int)tree_path.size()?
            node_to_art[tree_path[i + 1] - cnt_bicon]:
            -1
        );

        if(!append_hem_cycle(tree_path[i], head, tail)) 
            still_possible = 0;
        
        head = tail;
    }
    
    if(still_possible)
        output_final_path();
    else
        output_imp();
    return 0;    
}