Cod sursa(job #3289744)

Utilizator BledeaAlexBledea Alexandru BledeaAlex Data 28 martie 2025 12:56:36
Problema Santa Scor 0
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 5.86 kb
#include <bits/stdc++.h>

using namespace std;

/// OBS: Fiecare comp biconexa are cel mult 15 noduri !!!
const int NR_MAX = 16, ST_MAX = 1 << NR_MAX;

int S, E, Q;

const int INF = 1e9 + 5;

vector<bool> visited;
vector<vector<int> > G;
vector<int> level, low;
stack<int> Stack;

vector<bool> isCriticalNode;
vector<pair<int, int> > criticalEdges;
vector<vector<int> > biconex;
vector<int> comp;

void SetInput(string name)
{
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);

    (void)!freopen((name + ".in").c_str(), "r", stdin);
    (void)!freopen((name + ".out").c_str(), "w", stdout);
}

void FinishProgram()
{
    cout << "No chance\n";
    exit(0);
}

void DFS_CB(int v, int t, int root) /// Pentru a calcula comp biconexe
{
    visited[v] = true;
    low[v] = level[v] = level[t] + 1;

    Stack.push(v);

    int nrChildren = 0;

    for(const int u : G[v])
        if(u != t)
        {
            if(visited[u])
            {
                low[v] = min(low[v], level[u]);
                continue;
            }

            DFS_CB(u, v, root);
            low[v] = min(low[v], low[u]);

            nrChildren++;

            if(v != root && level[v] <= low[u])
                isCriticalNode[v] = true;

            if(level[v] < low[u])
                criticalEdges.emplace_back(v, u);

            if(level[v] <= low[u])
            {
                biconex.push_back(vector<int>(0));

                int x;
                do{
                    x = Stack.top();
                    Stack.pop();
                    biconex[biconex.size() - 1].push_back(x);
                    comp[x] = biconex.size() - 1;
                } while(x != u);

                biconex[biconex.size() - 1].push_back(v);
                comp[v] = biconex.size() - 1;
            }
        }

    if(v == root && nrChildren >= 2)
        isCriticalNode[root] = true;
}

vector<int> crPath, path;
vector<int> crCriticalNodesInPath, criticalNodesInPath;
vector<bool> visited_2;

void DFS(int v) /// Pentru a calcula prin ce comp biconexe trece drumul de la S la E
{
    visited_2[v] = true;
    crPath.push_back(comp[v]);

    if(v == E)
    {
        path = crPath;
        criticalNodesInPath = crCriticalNodesInPath;
        return;
    }

    for(const int u : G[v])
        if(not visited_2[u])
        {
            if(comp[v] != comp[u]) crCriticalNodesInPath.push_back(v);
            DFS(u);
            if(comp[v] != comp[u]) crCriticalNodesInPath.pop_back();
        }

    crPath.pop_back();
}

vector<int> answer;
struct HamiltonianNode
{
    bool possible;
    int lastNode;

    HamiltonianNode() { }

    HamiltonianNode(bool _possible, int _last) :
        possible(_possible), lastNode(_last) { }
};

HamiltonianNode dp[ST_MAX][16]; /// dp[mask][v] daca se poate face un drum hamiltonian care se termina cu v cu nodurile din mask
unordered_map<int, int> nodeId;
unordered_map<int, int> revNodeId;

void AddToAns(int first, int crr, int mask)
{
    if(crr == first)
        return;

    // cerr << crr << ' ' << dp[mask][nodeId[crr]].lastNode << ' ' << mask << '\n';

    AddToAns(first, dp[mask][crr].lastNode, (mask ^ (1 << crr)));

    answer.push_back(revNodeId[crr]);
}

void FindPathInCompBiconex(int id, int first, int last)
{
    int cnt = biconex[id].size();
    int maxMask = (1 << cnt) - 1;
    nodeId.clear();
    for(int i = 0; i < biconex[id].size(); i++)
    {
        int u = biconex[id][i];
        nodeId[u] = i;
        revNodeId[i] = u;
    }

    for(int mask = 0; mask <= maxMask; mask++)
        for(int i = 0; i < cnt; i++)
            dp[mask][i] = HamiltonianNode(false, -1);

    dp[1 << nodeId[first]][nodeId[first]] = HamiltonianNode(true, -1);

    for(int mask = 0; mask < maxMask; mask++)
        for(int i = 0; i < cnt; i++)
        {
            if(not dp[mask][i].possible)
                continue;

            for(const int u : G[revNodeId[i]])
                if(nodeId.count(u) != 0 && (mask & (1 << nodeId[u])) == 0)
                    dp[mask ^ (1 << nodeId[u])][nodeId[u]] = HamiltonianNode(true, i);
        }

    if(last != -1)
    {
        if(not dp[maxMask][nodeId[last]].possible)
            FinishProgram();

        AddToAns(nodeId[first], last, maxMask);
    }
    else
    {
        for(int i = 0; i < cnt; i++)
            if(dp[maxMask][i].possible)
            {
                AddToAns(nodeId[first], i, maxMask);
                return;
            }
        FinishProgram();
    }
}

void Solve()
{
    int N, M;

    cin >> N >> M;

    G.resize(N + 1);
    visited.resize(N + 1, false);
    isCriticalNode.resize(N + 1, false);
    level.resize(N + 1, INF);
    low.resize(N + 1, INF);
    comp.resize(N + 1, -1);

    for(int i = 1, u , v; i <= M; i++)
    {
        cin >> u >> v;
        G[u].push_back(v);
        G[v].push_back(u);
    }

    cin >> S >> E >> Q;


    DFS_CB(S, 0, S);

    if(not visited[S]) /// Nu exista un drum de la S la E
        FinishProgram();

    if(find(biconex[comp[S]].begin(), biconex[comp[S]].end(), Q) == biconex[comp[S]].end()) /// S si Q NU sunt in aceeasi comp biconexa
        FinishProgram();

    visited_2.resize(N + 1, false);
    DFS(S);

    path.erase(unique(path.begin(), path.end()), path.end());
    criticalNodesInPath.insert(criticalNodesInPath.begin(), Q);
    answer.push_back(Q);

    for(int i = 0; i < path.size(); i++)
        if(i == path.size() - 1)
            FindPathInCompBiconex(path[i], criticalNodesInPath[i], -1);
        else
            FindPathInCompBiconex(path[i], criticalNodesInPath[i], criticalNodesInPath[i+1]);

    cout << answer.size() << '\n';
    for(int v : answer)
        cout << v << ' ';
}

int main()
{
    SetInput("santa");

    FinishProgram();
    Solve();

    return 0;
}