Cod sursa(job #1165720)

Utilizator tzipleatudTudor Tiplea tzipleatud Data 2 aprilie 2014 21:10:21
Problema Santa Scor 0
Compilator cpp Status done
Runda Lista lui wefgef Marime 8.49 kb
#include <fstream>
#include <vector>
#include <algorithm>
#include <set>
#include <cassert>
#include <stack>
#include <cstring>

using namespace std;

ifstream f("santa.in");
ofstream g("santa.out");

int N, M, T;
int CntComponents, CntCritical;
int S, E, Q;
vector< vector<int> > G;
vector< vector<int> > Tree;
vector<int> Level, LowPoint, WComponent, WCritical;
vector<bool> IsCritical;
vector<int> Critical, CountComponents;
vector< vector<int> > Components;
vector<int> Path, Itinerary;
vector<int> Pos, IsHere;
vector<int> ANS;
bool solution=1;

stack< pair<int, int> > Stack;

void Read ()
{
    f >> N >> M;

    G.resize(N);
    Level.resize(N, 0);
    LowPoint.resize(N, 0);
    WComponent.resize(N, 0);
    IsCritical.resize(N, 0);
    WCritical.resize(N, 0);
    Pos.resize(N, 0);
    IsHere.resize(N, 0);
    CountComponents.resize(N, 0);

    for (int i=0; i<M; i++)
    {
        int a, b;
        f >> a >> b;
        G[a-1].push_back(b-1);
        G[b-1].push_back(a-1);
    }

    f >> S >> E >> Q;
    S--;
    E--;
    Q--;
}

void DF (int node, int father)
{
    LowPoint[node]=Level[node];

    for (vector<int>::iterator it=G[node].begin(); it!=G[node].end(); ++it)
    {
        if (*it==father)
            continue;

        if (Level[*it]==0)
        {
            Level[*it]=Level[node]+1;
            Stack.push(make_pair(node, *it));
            DF(*it, node);

            LowPoint[node]=min(LowPoint[node], LowPoint[*it]);

            if (LowPoint[*it]>=Level[node])
            {
                vector<int> Aux;
                Aux.clear();
                for (; !Stack.empty() && Stack.top()!=make_pair(node, *it); Stack.pop())
                {
                    Aux.push_back(Stack.top().first);
                    Aux.push_back(Stack.top().second);
                }

                if (!Stack.empty() && Stack.top()==make_pair(node, *it))
                {
                    Aux.push_back(Stack.top().first);
                    Aux.push_back(Stack.top().second);
                    Stack.pop();
                }

                sort(Aux.begin(), Aux.end());
                Aux.resize(unique(Aux.begin(), Aux.end()) - Aux.begin());

                assert(Aux.size()<=20);
                for (int i=0; i<(int)Aux.size(); i++)
                    CountComponents[Aux[i]]++;

                Components.push_back(Aux);
            }
        }
        else
            LowPoint[node]=min(LowPoint[node], Level[*it]);
    }
}

void DoBiconnected ()
{
    for (int i=0; i<N; i++)
        if (Level[i]==0)
        {
            Level[i]=1;
            DF(i, -1);
        }

    for (int i=0; i<N; i++)
        if (CountComponents[i]>=2)
        {
            Critical.push_back(i);
            IsCritical[i]=1;
        }

    sort(Critical.begin(), Critical.end());
    Critical.resize(unique(Critical.begin(), Critical.end()) - Critical.begin());

    for (vector<int>::iterator it=Critical.begin(); it!=Critical.end(); ++it)
        WCritical[*it]=it - Critical.begin();

    CntCritical=Critical.size();
    CntComponents=Components.size();
    T=CntCritical + CntComponents;
    Tree.resize(T);

    for (int i=0; i<(int)Components.size(); i++)
        for (vector<int>::iterator it=Components[i].begin(); it!=Components[i].end(); ++it)
            if (IsCritical[*it]==1)
            {
                Tree[CntComponents + WCritical[*it]].push_back(i);
                Tree[i].push_back(CntComponents + WCritical[*it]);
            }
            else
                WComponent[*it]=i;
}

bool DFTree (int node, int father, int end)
{
    Path.push_back(node);
    if (node==end)
        return 1;
    bool found=0;

    for (vector<int>::iterator it=Tree[node].begin(); it!=Tree[node].end(); ++it)
        if (*it!=father)
        {
            found|=DFTree(*it, node, end);
            if (found)
                return 1;
        }

    Path.pop_back();
    return 0;
}

int n, endnode;
vector<int> Edge[20];
bool viz[20];
bool found;
int aux[20];

void Back (int p)
{
    if (p>=n)
    {
        found=1;
        return;
    }

    for (vector<int>::iterator it=Edge[aux[p-1]].begin(); it!=Edge[aux[p-1]].end() && found==0; ++it)
        if (!viz[*it] && (*it!=endnode || p==n-1))
        {
            viz[*it]=1;
            aux[p]=*it;
            Back(p+1);
            viz[*it]=0;
        }
}

void DoBack (int hash, int start, vector<int>& V, int end)
{
    n=V.size();

    for (int i=0; i<n; i++)
    {
        Pos[V[i]]=i;
        IsHere[V[i]]=hash;
    }

    for (int i=0; i<20; i++)
    {
        Edge[i].clear();
        aux[i]=0;
        viz[i]=0;
    }

    for (int i=0; i<n; i++)
        for (vector<int>::iterator it=G[V[i]].begin(); it!=G[V[i]].end(); ++it)
            if (IsHere[*it]==hash)
                Edge[i].push_back(Pos[*it]);

    for (int i=0; i<n; i++)
        if (V[i]==start)
        {
            start=i;
            break;
        }

    for (int i=0; i<n; i++)
        if (V[i]==end)
        {
            end=i;
            break;
        }

    aux[0]=start;
    viz[start]=1;
    found=0;
    endnode=end;
    Back(1);
    viz[start]=0;

    for (int i=0; i<n; i++)
        ANS.push_back(aux[i]);
}

void Go ()
{
    for (int i=1; i<(int)Itinerary.size(); i+=2)
        DoBack(i, Itinerary[i-1], Components[Itinerary[i]], Itinerary[i+1]);
}

void FindPath ()
{
    int start, end;

    if (IsCritical[S])
        start=CntComponents + WCritical[S];
    else
        start=WComponent[S];

    if (IsCritical[E])
        end=CntComponents + WCritical[E];
    else
        end=WComponent[E];

    DFTree(start, -1, end);

    int first=-1, last=-1;

    for (vector<int>::iterator it=Path.begin(); it!=Path.end(); ++it)
        if (*it<CntComponents)
        {
            first=*it;
            break;
        }

    for (vector<int>::reverse_iterator it=Path.rbegin(); it!=Path.rend(); ++it)
        if (*it<CntComponents)
        {
            last=*it;
            break;
        }

    if (first<0 || last<0)
        return;

    bool found=0;
    for (vector<int>::iterator it=Components[first].begin(); it!=Components[first].end(); ++it)
        if (*it==Q)
        {
            found=1;
            break;
        }

    if (found)
    {
        for (int i=0; i<(int)Path.size(); i++)
            if (Path[i]==first)
            {
                Itinerary.push_back(Q);
                for (int j=i; j<(int)Path.size(); j++)
                    if (Path[j]<CntComponents)
                        Itinerary.push_back(Path[j]);
                    else
                        Itinerary.push_back(Critical[Path[j] - CntComponents]);

                if (Itinerary.size()%2==1)
                    Itinerary[Itinerary.size()-1]=-1;

                if (Itinerary.size()%2==0)
                    Itinerary.push_back(-1);

                Go();
                return;
            }
        return;
    }

    for (vector<int>::iterator it=Components[last].begin(); it!=Components[last].end(); ++it)
        if (*it==Q)
        {
            found=1;
            break;
        }

    if (found)
    {
        for (int i=Path.size()-1; i>=0; i--)
            if (Path[i]==last)
            {
                Itinerary.push_back(Q);
                for (int j=i; j>=0; j--)
                    if (Path[j]<CntComponents)
                        Itinerary.push_back(Path[j]);
                    else
                        Itinerary.push_back(Critical[Path[j] - CntComponents]);

                if (Itinerary.size()%2==1)
                    Itinerary[Itinerary.size()-1]=-1;

                if (Itinerary.size()%2==0)
                    Itinerary.push_back(-1);

                Go();
                return;
            }
        return;
    }
}

void Print ()
{
    vector<int> aux;
    for (int i=0; i<(int)ANS.size(); i++)
        if (i==0)
            aux.push_back(ANS[i]);
        else
            if (ANS[i]!=ANS[i-1])
                aux.push_back(ANS[i]);

    if (aux.size()==0 || solution==false)
        g << "No chance\n";
    else
    {
        g << aux.size() << '\n';
        for (int i=0; i<(int)aux.size(); i++)
            g << aux[i]+1 << ' ';
        g << '\n';
    }
}

int main ()
{
    Read();
    DoBiconnected();
    FindPath();
    Print();

    f.close();
    g.close();

    return 0;
}