Cod sursa(job #1304962)

Utilizator geniucosOncescu Costin geniucos Data 29 decembrie 2014 14:02:27
Problema Santa Scor 0
Compilator cpp Status done
Runda Lista lui wefgef Marime 9.46 kb
#include<cstdio>
#include<vector>
#include<stack>
#include<algorithm>

using namespace std;

int Begin, End, N_Back, S, E, Q, nr_comp_on_line, nr_componente_conexe, Nr, N, M, Cod_Back[45009], how[90009], niv[45009], cod_nod[45009], dp[45009], componenta_conexa[45009], cod_componenta_biconexa[45009], any_component[45009], first_component, last_component, real_nod_for_cod[90009], Left[45009], Right[45009], comp[45009], how_dp[17][(1<<15)+3];
bool Finish, IsCriticalNode[45009], IsComponent[90009], se_poate;

stack  < pair < int , int > > stiva_muchii;
vector < int > muchii[45009], tree_edges[90009], critical_nodes, drum, answer;
vector < vector < int > > componente;

void unific (vector < int > &v)
{
    sort (v.begin(), v.end());
    v.erase (unique (v.begin(), v.end()), v.end());
}

void Add_Componenta (pair < int , int  > fin)
{
    vector < int > comp;
    pair < int, int > top;
    do
    {
        top = stiva_muchii.top();
        stiva_muchii.pop();
        comp.push_back (top.first);
        comp.push_back (top.second);
    }while (top != fin);
    unific (comp);
    componente.push_back (comp);
}

void dfs (int nod, int tata)
{
    dp[nod] = niv[nod];
    componenta_conexa[nod] = nr_componente_conexe;
    for (vector < int > :: iterator it = muchii[nod].begin(); it != muchii[nod].end(); it ++)
        if (niv[*it] == -1)
        {
            niv[*it] = niv[nod] + 1;
            stiva_muchii.push (make_pair (nod, *it));
            dfs (*it, nod);

            if (dp[*it] > niv[nod]) ;/////critical edge intre *it si nod

            if (dp[*it] >= niv[nod])
            {
                critical_nodes . push_back (nod);
                IsCriticalNode [nod] = 1;
                Add_Componenta (make_pair (nod, *it));
            }
        }

    bool deja_tata = 0;
    for (vector < int > :: iterator it = muchii[nod].begin(); it != muchii[nod].end(); it++)
    {
        if (*it == tata && deja_tata == 0)
            deja_tata = 1;
        else
            dp[nod] = min (dp[nod], dp[*it]);
    }
}

void afis_componente_biconexe ()
{
    printf ("%d\n", componente.size());
    for (int i=0; i<componente.size(); i++, printf ("\n"))
        for (vector < int > :: iterator it = componente[i].begin(); it != componente[i].end(); it++)
            printf ("%d ", *it);
}

void Add_Edge_In_Tree (int X, int Y)
{
    tree_edges[X].push_back (Y);
    tree_edges[Y].push_back (X);
}

void Refresh_Components()
{
    for (int i=0; i<componente.size(); i++)
        for (vector < int > :: iterator it = componente[i].begin(); it != componente[i].end(); it ++)
            any_component[*it] = i;
}

void Make_Codes_And_Tree ()
{
    Refresh_Components ();

    for (int i=1; i<=N; i++)
        if (IsCriticalNode [i] && componenta_conexa [i] == componenta_conexa[Q])
        {
            cod_nod[i] = ++Nr;
            real_nod_for_cod[Nr] = i;
        }

    for (int i=0; i<componente.size(); i++)
        if (componenta_conexa [componente[i][0]] == componenta_conexa [Q])
        {
            cod_componenta_biconexa [i] = ++Nr;
            real_nod_for_cod [Nr] = i;
            IsComponent[Nr] = 1;
            for (vector < int > :: iterator it = componente[i].begin(); it != componente[i].end(); it ++)
                if (IsCriticalNode[*it])
                    Add_Edge_In_Tree (cod_nod[*it], cod_componenta_biconexa [i]);
        }
}

void Dfs_In_Tree (int nod)
{
    for (vector < int > :: iterator it = tree_edges[nod].begin(); it != tree_edges[nod].end(); it ++)
        if (how[*it] == 0)
        {
            how[*it] = nod;
            Dfs_In_Tree (*it);
        }
}

void afis ()
{
    if (se_poate == 0)
    {
        printf ("No chance\n");
        return;
    }
    printf ("%d\n", answer.size());

    printf ("%d ", answer[0]);
    for (int i=1; i<answer.size(); i++)
        if (answer[i] != answer[i-1]) printf ("%d ", answer[i]);

    printf ("\n");
}

void back (int nod, int sfarsit, int msk)
{
    if (Finish) return;
    if (msk == (1<<N_Back) - 1 && nod == sfarsit)
    {
        Finish = 1;
        return;
    }
    for (vector < int > :: iterator it = muchii[nod].begin(); it != muchii[nod].end(); it ++)
    {
        int bit = Cod_Back[*it];
        if (msk & (1<<bit)) continue;
        if (how_dp[bit][msk|(1<<bit)] == 0)
        {
            how_dp[bit][msk|(1<<bit)] = Cod_Back[nod];
            back (*it, sfarsit, msk | (1<<bit));
        }
    }
}

vector < int > calc_drum_in_biconexa (int index_componenta, int start, int sfarsit)
{
    N_Back = 0;
    for (vector < int > :: iterator it = componente[index_componenta].begin(); it != componente[index_componenta].end(); it ++)
        Cod_Back[*it] = N_Back ++;
    Finish = 0;
    back (start, sfarsit, 1<<Cod_Back[start]);

    vector < int > ans;
    if (Finish)
    {
        int nod = Cod_Back[sfarsit], msk = (1<<N_Back) - 1;
        ans.push_back (sfarsit);
        while (nod != Cod_Back[start])
        {
            int new_msk = msk - (1 << nod);
            nod = how_dp[nod][msk];
            msk = new_msk;
            ans.push_back (componente[index_componenta][nod]);
        }
        reverse (ans.begin(), ans.end());
    }
    else
        ans.push_back (-1);

    for (int i=0; i<(1<<N_Back); i++)
        for (int j=0; j<N_Back; j++)
            how_dp[i][j] = 0;
    return  ans;
}

void Add_To_Answer (vector < int > v)
{
    for (vector < int > :: iterator it = v.begin(); it != v.end(); it++)
        answer.push_back (*it);
}

int main()
{
freopen ("santa.in", "r", stdin);
freopen ("santa.out", "w", stdout);

scanf ("%d %d", &N, &M);
for (int i=1; i<=M; i++)
{
    int X, Y;
    scanf ("%d %d", &X, &Y);
    muchii[X].push_back(Y);
    muchii[Y].push_back(X);
}
scanf ("%d %d %d", &S, &E, &Q);

for (int i=1; i<=N; i++)
    niv[i] = -1;

for (int i=1; i<=N; i++)
    if (niv[i] == -1)
    {
        nr_componente_conexe ++;
        niv[i] = 0;
        dfs (i, 0);
    }

if (componenta_conexa[S] != componenta_conexa[E] || componenta_conexa[S] != componenta_conexa[Q] || componenta_conexa[E] != componenta_conexa[Q])
{
    printf ("No chance\n");
    return 0;
}

////voi face arborele componentelor biconexe cu nodurile critice
Make_Codes_And_Tree ();

if (IsCriticalNode [S]) Begin = cod_nod[S], Dfs_In_Tree (Begin);
else Begin = cod_componenta_biconexa[any_component[S]], Dfs_In_Tree (Begin);

if (IsCriticalNode [E]) End = cod_nod[E];
else End = cod_componenta_biconexa[any_component[E]];

int nod = End;
drum.push_back (End);
while (nod != Begin)
{
    nod = how[nod];
    drum.push_back (nod);
}
reverse (drum.begin(), drum.end());

for (int i=0; i<drum.size(); i++)
    if (IsComponent[drum[i]])
    {
        first_component = real_nod_for_cod[drum[i]];
        break;
    }

for (int i=drum.size() - 1; i>=0; i--)
    if (IsComponent[drum[i]])
    {
        last_component = real_nod_for_cod[drum[i]];
        break;
    }

if (IsCriticalNode[Q])
{
    bool ok = 0;
    for (vector < int > :: iterator it = componente[first_component].begin(); it != componente[first_component].end(); it ++)
        if (*it == Q)
        {
            ok = 1;
            break;
        }
    if (ok == 0)
    {
        for (vector < int > :: iterator it = componente[last_component].begin(); it != componente[last_component].end(); it ++)
            if (*it == Q)
            {
                ok = 1;
                break;
            }
        if (ok == 0)
        {
            printf ("No chance\n");
            return 0;
        }
        reverse (drum.begin(), drum.end());
    }
}
else
{
    if (last_component != any_component[Q] && first_component != any_component[Q])
    {
        printf ("No chance\n");
        return 0;
    }
    if (first_component == any_component[Q]) ;
    else reverse (drum.begin(), drum.end());
}

///////practic acum drum reprezinta un vector de componente biconexe si noduri critice in care prima componenta biconexa il contine pe Q

se_poate = 1;
for (int i=0; i<drum.size(); i++)
    if (IsComponent[drum[i]])
    {
        int inceput, sfarsit;

        if (i<=1) inceput = Q;
        else inceput = real_nod_for_cod[drum[i-1]];

        if (drum.size() - 1 - i > 1) sfarsit = real_nod_for_cod[drum[i+1]];
        else sfarsit = -1;

        nr_comp_on_line ++;
        comp[nr_comp_on_line] = real_nod_for_cod [drum[i]];
        Left[nr_comp_on_line] = inceput;
        Right[nr_comp_on_line] = sfarsit;
    }

for (int i=1; i<=nr_comp_on_line; i++)
{
    if (Right[i] == -1)
    {
        bool ok = 0;
        for (vector < int > :: iterator it = componente[comp[i]].begin(); it != componente[comp[i]].end(); it ++)
            if (*it != Left[i])
            {
                vector < int > drum_in_biconexa = calc_drum_in_biconexa(comp[i], Left[i], *it);
                if (drum_in_biconexa[0] != -1)
                {
                    ok = 1;
                    Add_To_Answer (drum_in_biconexa);
                    break;
                }
            }
        if (ok == 0)
        {
            printf ("No chance\n");
            return 0;
        }
        continue;
    }
    vector < int > drum_in_biconexa = calc_drum_in_biconexa(comp[i], Left[i], Right[i]);
    if (drum_in_biconexa[0] == -1)
    {
        printf ("No chance\n");
        return 0;
    }
    Add_To_Answer (drum_in_biconexa);
}

afis ();

return 0;
}