Cod sursa(job #455349)

Utilizator toni2007Pripoae Teodor Anton toni2007 Data 13 mai 2010 16:42:46
Problema Santa Scor 80
Compilator cpp Status done
Runda Arhiva de probleme Marime 10.3 kb
#include <stdio.h>
#include <set>
#include <vector>
#include <utility>
#include <bitset>
#include <algorithm>
#include <map>
#include <cstring>

using namespace std;

#define maxN    45100
#define maxM    130100
#define oo      45100
#define ROOT    1

int N, M, Nr, cate_ramase, E, Q, S, Global_ok;
int low[maxN], nivel[maxN];
int Biconexa[maxM];
int A[maxN], B[maxN], Sol, Z[20][20], Grad[20], st[20], in_st[20], Ok;
vector <int> G[maxN], Ind[maxN], ind, stiva, stiva_noduri, X[maxN];
vector < pair <int, int> > stack;
set <int> Sol_vec[maxN];
bitset <maxN> art_point, viz, D[16];
map <int, int> Map;

void no_chance () {
    printf("No chance\n");
    exit(0);
}

void baga_marfa () {
    Sol_vec[Nr].insert(stack.back().first);                 // adaug cele 2 noduri la biconexa, in caz ca mai sunt deja nu apar de 2 ori
    Sol_vec[Nr].insert(stack.back().second);
    Biconexa[ind.back()] = Nr;                              // tin minte din ce biconexa face parte muchia
    stack.pop_back();                                       // scot ultima muchie din stiva
    ind.pop_back();
}

void df (int nod, int parinte) {
    int niv_min = oo;                               // nivelul minim la care pot ajunge din descendenti + muchie de intoarcere

    viz[nod] = 1;                                   // marchez nodul ca vizitat
    nivel[nod] = nivel[parinte] + 1;                // nivelul nodului este nivelul parintelui + 1
    cate_ramase --;                                 // am mai vizitat un nod, scad numarul celor nevizitate
    low[nod] = nivel[nod];                          // momentan nivelul minim la care se poate ajunge din nodul curent in sus este nivelul lui

    for (vector <int> :: iterator it = G[nod].begin(); it != G[nod].end(); ++ it) {     // parcurg vecinii
        if (*it == parinte || (viz[*it] && nivel[*it] > nivel[nod]))     continue;      // in caz ca e parintele ma opresc

        stack.push_back(make_pair(nod, *it));                                           // bag muchia curenta in stiva
        ind.push_back(Ind[nod][it - G[nod].begin()]);                                   // si indicele ei, o sa ma ajute mai tarziu la reconstructie

        if (viz[*it]) {                                                                 // daca a mai fost vizitat, e muchie de intoarcere
            low[nod] = min(low[nod], nivel[*it]);                                       // vad daca pot ajunge mai sus decat pana acum
        } else {
            df(*it, nod);                                                               // ma duc pe muchia de dus
            niv_min = min(niv_min, low[*it]);                                           // modific corespunzator nivelul minim la care se poate ajunge din fii

            if (low[*it] >= nivel[nod] && nod != ROOT) {                                // daca toti descendentii lui ajung maxim pana la nivelul lui
                art_point[nod] = 1;                                                     // e punct de articulatie
                ++ Nr;                                                                  // apare o noua biconexa

                for (; stack.back() != make_pair(nod, *it); baga_marfa());
                baga_marfa();                                                           // scot din stiva pana ajung la muchia curenta, inclusiv ea.
            }
        }

        if (nod == ROOT && cate_ramase) {                                               // ma uit daca nu e nodul 1 punct de articulatie
            art_point[nod] = 1;
            ++ Nr;

            for (; stack.back() != make_pair(nod, *it); baga_marfa());                  // adaug biconexa
            baga_marfa();
        }
    }

    low[nod] = min(low[nod], niv_min);                                                  // marchez nivelul minim la care poate ajunge
}

void dfs (int nod) {
    int am_pus;                                                                         // tin minte daca am pus muchie in stiva

    viz[nod] = 1;                                                                       // marchez nodul ca vizitat

    if (nod == E) {                                                                     // in caz ca am ajuns la destinatie marchez, ca sa imi pastrez stiva
        Global_ok = 1;
        stiva_noduri.push_back(E);
    }

    for (vector <int> :: iterator it = G[nod].begin(); it != G[nod].end(); ++ it) {     // parcurg vecinii
  //      fprintf(stderr, "%d %d\n", nod, *it);
        if (! viz[*it] && ! Global_ok) {                                                // in caz ca a fost vizitat sau am ajuns deja la destinatie
    //        fprintf(stderr, "%d %d\n", nod, *it);
            if (! stiva.size() || stiva.back() != Biconexa[Ind[nod][it - G[nod].begin()]]) {
                am_pus = 1;                                                             // pun muchie si tine minte ca am pus, ca sa o scot dupa
                stiva.push_back(Biconexa[Ind[nod][it - G[nod].begin()]]);
                stiva_noduri.push_back(nod);
            } else
                am_pus = 0;
            
            dfs(*it);                                                                   // ma duc in fiu
            if (Global_ok)                                                              // in caz ca am ajuns la destinatie ies
                return;

            if (am_pus) {                                                               // daca am pus muchie acum o scot
                stiva.pop_back();
                stiva_noduri.pop_back();
            }
        }
    }
}

void back (int poz, int nr) {
    /*printf("Ce e pe stiva (%d %d) : ", poz, nr);
    for (int i = 0; i <= nr; ++ i)
        printf("%d ", st[i]);
    puts("");
*/
    if (poz == nr) {
        if (Z[st[poz - 1]][st[poz]])
            Ok = 1;
        return ;
    }

    for (int i = 0; i < nr; ++ i) {
  //      printf("Ok = %d ; st[poz - 1] = %d, i = %d, Z[st[poz - 1]][i] = %d, in_st[i] = %d\n", Ok, st[poz - 1], i, Z[st[poz - 1]][i], in_st[i]);
        if (! Ok && (Z[st[poz - 1]][i] && ! in_st[i])) {
            st[poz] = i;
            in_st[i] = 1;
            back(poz + 1, nr);
            in_st[i] = 0;
        }
    }
}

inline bool cmp (int a, int b) {
    return Grad[a] < Grad[b];
}

void hamilton (int biconexa, int ind) {
    vector <int> indi;
    int i, nr, s, e, j;

    s = stiva_noduri[ind - 1];
    e = stiva_noduri[ind];

    indi.push_back(s);

  //  printf("Biconexa: %d, ind = %d : capete (%d %d)\n", biconexa, ind, stiva_noduri[ind - 1], stiva_noduri[ind]);
    for (set <int> :: iterator it = Sol_vec[biconexa].begin(); it != Sol_vec[biconexa].end(); ++ it) {
        if (*it == s || *it == e)
            continue;
        indi.push_back(*it);
    }

    indi.push_back(e);

    nr = indi.size();
    memset(Z, 0, sizeof(Z));
    memset(Grad, 0, sizeof(Grad));
    memset(st, 0, sizeof(st));
    memset(in_st, 0, sizeof(in_st));

    for (i = 0; i < nr; ++ i)
        Map[indi[i]] = i;
/*
    for (i = 0; i < nr; ++ i)
        printf("Map[%d] = %d ", indi[i], i);
    puts("");

    for (i = 0; i < nr; ++ i)
        printf("Ind[%d] = %d ", i, indi[i]);
*/
    for (i = 0; i < nr; ++ i)
        for (vector <int> :: iterator it2 = G[indi[i]].begin(); it2 != G[indi[i]].end(); ++ it2) {
            if (Sol_vec[biconexa].find(*it2) == Sol_vec[biconexa].end())    continue;
            Z[i][Map[*it2]] = 1;
    //        printf("Trag muchie %d %d\n", i, Map[*it2]);
        }

    for (i = 0; i < nr; ++ i) {
        for (j = 0; j < nr; ++ j)
            Grad[i] += Z[i][j];
    }

//    if (nr >= 3)
  //      sort(indi.begin() + 1, indi.end() - 1, cmp);

    st[0] = 0; in_st[0] = 1;
    st[nr - 1] = nr - 1; in_st[nr - 1] = 1;
    Ok = 0;

    back(1, nr - 1);

    if (! Ok)
        no_chance();

    for (i = 0; i < nr - 1; ++ i) {
    //    printf("(%d %d) ", st[i], indi[st[i]]);
        X[ind].push_back(indi[st[i]]);
        ++ Sol;
    }
   // puts("");
}

int main () {
    int i, a, b;

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

    scanf("%d%d", &N, &M);  // citesc numarul de noduri si numarul de muchii

    for (i = 1; i <= M; ++ i) {
        scanf("%d%d", &A[i], &B[i]);      // citesc muchiile

        G[A[i]].push_back(B[i]);          // construiesc graful
        G[B[i]].push_back(A[i]);

        Ind[A[i]].push_back(i);        // tin minte indicii muchiilor
        Ind[B[i]].push_back(i);

    }

    cate_ramase = N;                // cate noduri nu au fost vizitate
    df(ROOT, 0);                       // parcurg in adancime

    if (stack.size()) {
        ++ Nr;
        for (; stack.size(); baga_marfa());
    }

    /*printf("%d\n", Nr);

    for (i = 1; i <= Nr; ++ i) {
        for (set <int> :: iterator it = Sol_vec[i].begin(); it != Sol_vec[i].end(); ++ it)
            printf("%d ", *it);
        puts("");
    }*/
    scanf("%d%d%d", &S, &E, &Q);

    viz.reset();
    dfs(S);
/*
    for (i = 0; i < (int) stiva.size(); ++ i)
        printf("%d ", stiva[i]);
    puts("");
    for (i = 0; i < (int) stiva_noduri.size(); ++ i)
        printf("%d ", stiva_noduri[i]);
    puts("");
*/
    if (Sol_vec[stiva[0]].find(Q) == Sol_vec[stiva[0]].end() && Sol_vec[stiva[stiva.size() - 1]].find(Q) == Sol_vec[stiva[stiva.size() - 1]].end())
        no_chance();
    if (Sol_vec[stiva[0]].find(Q) != Sol_vec[stiva[0]].end()) {
        if (stiva.size() > 1 && Q == stiva_noduri[1])       // e punct de articulatie
            no_chance();
    } else {
        if (stiva.size() > 1 && Q == stiva_noduri[stiva_noduri.size() - 2])
            no_chance();
    }

    if (Sol_vec[stiva[0]].find(Q) == Sol_vec[stiva[0]].end())
        reverse(stiva.begin(), stiva.end());
    stiva_noduri[0] = Q;

    if (stiva.size() == 1) {
        for (set <int> :: iterator it = Sol_vec[stiva[0]].begin(); it != Sol_vec[stiva[0]].end(); ++ it) {
            G[N + 1].push_back(*it);
            G[*it].push_back(N + 1);
        }

        Sol_vec[stiva[0]].insert(N + 1);
        stiva_noduri[1] = N + 1;
    }
    for (vector <int> :: iterator it = stiva.begin(); it != stiva.end(); ++ it)
        hamilton(*it, it - stiva.begin() + 1);

    if (stiva_noduri[1] != N + 1)
        Sol ++;

    printf("%d\n", Sol);

    for (i = 1; i <= (int) stiva.size(); ++ i)
        for (vector <int> :: iterator it = X[i].begin(); it != X[i].end(); ++ it)
            printf("%d ", *it);

    if (stiva_noduri[1] != N + 1)
        printf("%d\n", stiva_noduri[stiva_noduri.size() - 1]);
}