Cod sursa(job #979525)

Utilizator SRaduRadu Szasz SRadu Data 1 august 2013 21:12:41
Problema Santa Scor 100
Compilator cpp Status done
Runda Lista lui wefgef Marime 7.62 kb
#include <fstream>
#include <vector>
#include <stack>
#include <cstring>
#include <algorithm>
#include <iostream>

using namespace std;

const bool DEBUG = false;
const int B_MAX = 20;
const int MAX = 45005;

int N, M, S, End, Q;
int Level[MAX], highest[MAX], componentIndex[MAX], Idx[MAX], B[B_MAX];
int edgeExists[B_MAX][B_MAX];

bool ok;
bool isCritical[MAX], isEnding[MAX], Used[MAX];

vector<int> G[MAX], V[MAX], E[MAX], Drum, miniPath, Path;

vector< vector<int> > Components;

stack< pair<int, int> > stk;

void citire() {
    ifstream in("santa.in");
    in >> N >> M;
    for(int i = 1, A, B; i <= M; i++) {
        in >> A >> B;
        G[A].push_back(B);
        G[B].push_back(A);
    } in >> S >> End >> Q;
    in.close();
}

void getBiconnectedComponent(int X, int Y) {
    vector<int> Component; 
    int x, y;
    do {
        x = stk.top().first, y = stk.top().second;
        stk.pop();
        Component.push_back(x); Component.push_back(y);
    } while(x != X || y != Y);
    sort(Component.begin(), Component.end());
    Component.erase(unique(Component.begin(), Component.end()), Component.end());
    for(size_t i = 0; i < Component.size(); i++) 
        componentIndex[ Component[i] ] = Components.size();
    Components.push_back(Component);
}

void dfs(int nod, int dad, int level) {
    Level[nod] = highest[nod] = level;
    int sonCnt = 0, critic = 0;
    for(size_t i = 0; i < G[nod].size(); i++) {
        int dest = G[nod][i];
        if(dest == dad) continue;
        if(!Level[dest]) {
            sonCnt++;
            stk.push( make_pair(nod, dest) );
            dfs(dest, nod, level + 1);
            highest[nod] = min(highest[nod], highest[dest]);
            if(highest[dest] >= Level[nod]) {
                getBiconnectedComponent(nod, dest);
                critic = 1;
            }
        } else highest[nod] = min(highest[nod], Level[dest]);
    }
    if(!DEBUG && nod == 1) cerr << sonCnt << "\n";
    if(nod == dad)
        isCritical[nod] = (sonCnt > 1);
    else isCritical[nod] = critic;
}

void getBiconnectedComponents() {
    for(int i = 1; i <= N; i++) 
        if(!Level[i]) dfs(i, i, 1);
    for(int i = 1; i <= N; i++)
        if(isCritical[i])
            componentIndex[i] = -1;
}

bool validGraph() {
    bool isValid = false;
    for(size_t i = 0; i < Components.size(); i++) {
        bool QHere = false, SHere = false, EHere = false;
        for(size_t j = 0; j < Components[i].size(); j++) {
            int nod = Components[i][j];
            if(Q == nod) QHere = true;
            if(S == nod) SHere = true;
            if(End == nod) EHere = true;
        }
        if(QHere && (SHere || EHere)) isValid = true;
        isEnding[i] = EHere;
    } return isValid;
}

bool canReachEnd(int nod, int dad) {
    Drum.push_back(nod);
    //cerr << nod << " ";
    if((nod == End) || (nod > N && isEnding[nod - N - 1])) return true;
    for(size_t i = 0; i < V[nod].size(); i++) {
        int dest = V[nod][i];
        //cerr << dest << "\n";
        if(dest == dad) continue;
        if(canReachEnd(dest, nod)) return true;
    } Drum.pop_back(); 
    return false;
}

void buildGraph(const int &Component) {
    for(size_t i = 0; i < Components[ Component ].size(); i++) 
        Idx[ Components[ Component ][ i ] ] = i;
    for(size_t i = 0; i < Components[ Component ].size(); i++) {
        int nod = Components[ Component ][ i ];
        for(size_t j = 0; j < G[nod].size(); j++) {
            int dest = G[nod][j];
            if(Idx[dest] != -1) {
                E[ Idx[nod] ].push_back( Idx[dest] );
                edgeExists[ Idx[nod] ][ Idx[dest] ] = true;               
            }
        }
    }
}


void eraseGraph(const int &Component) {
    for(size_t i = 0; i < Components[ Component ].size(); i++) {
        int nod = Components[ Component ][ i ];
        E[i].clear();
        Idx[nod] = -1;
    } memset(edgeExists, 0, sizeof(edgeExists));
}

bool Back(int lastNode, const int &Component, const int &Finish) {
    int nod = B[lastNode];
    if(lastNode == (int)Components[ Component ].size() - 1) {
        if(Finish == -1) {
            bool isValid = false;
            for(size_t i = 0; i < E[nod].size(); i++) {
                int dest = E[nod][i];
                if(!Used[dest]) {
                    B[lastNode + 1] = dest; 
                    isValid = true;
                    break;
                }
            }
            if(!isValid) return false;
        } else {
            if(!edgeExists[ nod ][ Finish ]) return false;
            B[lastNode + 1] = Finish;
        }
        for(int i = 2; i <= lastNode + 1; i++) {
            Used[ B[i] ] = false;
            miniPath.push_back( Components[ Component ][ B[i] ] );
        } return true;
    }
    for(size_t i = 0; i < E[nod].size(); i++) {
        int dest = E[nod][i];
        if(Used[dest] || dest == Finish) continue;
        B[ lastNode + 1 ] = dest; Used[dest] = true;
        if( Back(lastNode + 1, Component, Finish) ) return true;
        B[ lastNode + 1 ] = 0; Used[dest] = false;
    } return false;
}

void getPathThroughBiconnectedComponent(const int &Component, const int &Start, const int &Stop) {
    buildGraph(Component);
    miniPath.clear();
    int startingNode = Idx[Start], endingNode = (Stop == -1 ? -1 : Idx[Stop]);
    B[1] = startingNode; Used[startingNode] = true;
    Back(1, Component, endingNode);
    B[1] = 0; Used[startingNode] = false;
    eraseGraph(Component);
}

bool getPath() {
    if(!validGraph()) {
        cerr << "Graph was not valid\n";
        return false;
    }
    int Start = (isCritical[Q] ? Q : componentIndex[Q] + N + 1), Stop;
    if(Start > N) Drum.push_back(Q);
    if(!canReachEnd(Start, 0)) {
        cerr << "Can't reach end\n";
        return false;
    }
    if(DEBUG) {
        for(size_t i = 0; i < Drum.size(); i++) 
            cerr << Drum[i] << " ";
        cerr << "\n";
    }
    Path.push_back(Q);
    for(size_t i = 0; i < Drum.size(); i++) {
        if(Drum[i] <= N) continue;
        Start = Drum[i - 1], Stop = (i + 1 < Drum.size() ? Drum[i + 1] : -1);
        getPathThroughBiconnectedComponent(Drum[i] - N - 1, Start, Stop);
        if(DEBUG) {
            cerr << Start << " " << Stop << "\n";
            for(size_t j = 0; j < miniPath.size(); j++)
                cerr << miniPath[j] << " ";
            cerr << "\n\n";
        }
        if( miniPath.empty() ) {
            cerr << "MINIPATH IS EMPTY\n";
            return false;
        }
        for(size_t j = 0; j < miniPath.size(); j++) 
            Path.push_back(miniPath[j]);
    } return true;
}

void buildTree() {
    for(size_t i = 0; i < Components.size(); i++) 
        for(size_t j = 0; j < Components[i].size(); j++) {
            int nod = Components[i][j];
            if(isCritical[nod]) {
                V[nod].push_back(N + i + 1);
                V[N + i + 1].push_back(nod);
                if(DEBUG) {
                    cerr << "ADDED EDGE FROM " << nod << " TO " << N + i + 1 << "\n";
                }
            }
        }
}

void solve() {
    getBiconnectedComponents();
    if(DEBUG) {
        for(size_t i = 0; i < Components.size(); i++) {
            for(size_t j = 0; j < Components[i].size(); j++)
                cerr << Components[i][j] << " ";
            cerr << "\n";
        }
        for(int i = 1; i <= N; i++)
            if(componentIndex[i] == -1) cerr << i << " ";
    }
    buildTree();
    memset(Idx, -1, sizeof(Idx));
    ok = getPath();
}

void afisare() {
    ofstream out("santa.out");
    if(ok) {
        out << Path.size() << "\n";
        for(size_t i = 0; i < Path.size(); i++) 
            out << Path[i] << " ";
        out << "\n";
    } else out << "No chance\n";
    out.close();
}

int main() {
    citire();
    solve();
    afisare();
}