Cod sursa(job #23263)

Utilizator filipbFilip Cristian Buruiana filipb Data 28 februarie 2007 15:42:33
Problema Santa Scor 0
Compilator cpp Status done
Runda Arhiva de probleme Marime 6.32 kb
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <vector>
#include <set>
#define min(a, b) ((a < b) ? a : b)
#define x first
#define y second
#define NMax 45005

using namespace std;

int N, S, E, Q;
vector<int> G[NMax];

int dfn[NMax], low[NMax], critic[NMax], timp = 0, nr_rad = 0;
pair<int, int> ST[NMax]; int h = 0;

int V_NOD[NMax][17], card[NMax]; int NR_B = 0;
vector<int> A[2 * NMax]; int U[NMax], d[NMax], len_d = 0;

set<int> ADIACENTA[NMax];
int EM[NMax][17][17];
int Res[NMax + 10005];

void extract_sieve(int a, int b)
{   
    set<int> M;
    set<int>::iterator it;
    
    NR_B++; M.clear();
    
    for (; h && (ST[h].x != a || ST[h].y != b); h--)
       M.insert(ST[h].x), M.insert(ST[h].y);
    if (h)
       M.insert(ST[h].x), M.insert(ST[h].y), h--;         
       
    for (it = M.begin(); it != M.end(); it++)
        V_NOD[NR_B][card[NR_B]++] = *it;
    
}

void dfs(int tata, int nod)
{
     vector<int>::iterator it;
     
     dfn[nod] = low[nod] = (timp++);
     
     for (it = G[nod].begin(); it != G[nod].end(); it++)
     {
        if (*it != tata && dfn[*it] < dfn[nod])
           h++, ST[h].x = nod, ST[h].y = *it;
           
        if (dfn[*it] == -1)
        {        
                               
           if (nod == S) nr_rad++;
 
           dfs(nod, *it);
           
           low[nod] = min(low[nod], low[*it]);
           if (low[*it] >= dfn[nod])
           {
              extract_sieve(nod, *it);
              critic[nod] = 1;            
           }               
        }
         else if (tata != *it)
              low[nod] = min(low[nod], dfn[*it]);
     }   
}

void make_tree(void)
{
     int i, j = NR_B, x;
     set<int>::iterator it;

     for (i = 1; i <= N; i++)
         if (critic[i])
            j++, critic[i] = j;

     for (i = 1; i <= NR_B; i++)
         for (j = 0; j < card[i]; j++)             
         {
             x = V_NOD[i][j];
             if (critic[x])
             {
                A[i].push_back(critic[x]);
                A[critic[x]].push_back(i);
             }
         }
         
     for (i = 1; i <= N; i++)
     {
         x = critic[i];
         if (x)
            V_NOD[x][card[x]++] = i;
     }
}

void dfs_tree(int nod)
{
     vector<int>::iterator it;
     
     dfn[nod] = 1;
     for (it = A[nod].begin(); it != A[nod].end(); it++)
         if (!dfn[*it])
         { U[*it] = nod; dfs_tree(*it); }
}

int find_vertex(int nod)
{
    int i, j;
    set<int>::iterator it;
    
    if (critic[nod]) return critic[nod];
    
    for (i = 1; i <= NR_B; i++)
        for (j = 0; j < card[i]; j++)
            if (V_NOD[i][j] == nod)
               return i;
        
    return 0;
}

void find_path(int x, int y)
{
    int i, stop, nr, p;

    memset(dfn, 0, sizeof(dfn));
     
    for (i = x, nr = 1; i; i = U[i], nr++) dfn[i] = nr;
    for (i = y; !dfn[i]; i = U[i]) d[++len_d] = i;
    if (i == x) { d[++len_d] = x; return; }
    
    stop = i;
    
    for (i = x, p = dfn[stop]; ; i = U[i])
    {
        d[len_d + p] = i; p--;
        if (i == stop) break;
    }
    len_d += dfn[stop];
          
}

int bit(int X, int nr)
{ return (X & (1 << nr)) != 0; }

int BS(int nod, int X)
{
    int l, r, m;
    
    l = 0; r = card[nod]-1;
    while (l <= r)
    {
          m = (l + r) / 2;
          if (V_NOD[nod][m] < X) l = m+1;
          else if (V_NOD[nod][m] > X) r = m-1;
          else return m;
    }
    
    return -1;
}

int st[18], uz[18], drum[18], OK;

void back(int nivel, int nod, int start, int finish)
{
     int i;
     
     if (nivel == card[nod]+1)
     {
        if (finish == -1 || st[nivel-1] == finish)
        {
           OK = 1;       
           for (i = 1; i <= card[nod]; i++)
               drum[i] = V_NOD[nod][st[i]];
        }
        
        return ;         
     }
     
     for (i = 0; i < card[nod] && !OK; i++)
         if (nivel == 1 || EM[nod][st[nivel-1]][i])
         {
            st[nivel] = i; uz[i] = 1; 
            back(nivel+1, nod, start, finish);
            uz[i] = 0;
         } 
}

void add_small_path(int nod, int start, int finish)
{
     int i, j, k, f;
     
     f = BS(nod, start);
     if (finish)
          finish = BS(nod, finish);       
     else finish = -1;        
     
     OK = 0;
     memset(uz, 0, sizeof(uz));
     back(1, nod, start, finish);                        
                   
     for (i = 1; i <= card[nod]; i++)
         Res[++Res[0]] = drum[i];     
}

int main(void)
{
    int M, i, x, y, z, from, to, a, b;
    
    freopen("santa.in", "r", stdin);
    freopen("santa.out", "w", stdout);
    
    scanf("%d %d", &N, &M);
    for (i = 1; i <= M; i++)
    {
        scanf("%d %d", &x, &y);
        G[x].push_back(y);
        G[y].push_back(x);        

        ADIACENTA[x].insert(y);
        ADIACENTA[y].insert(x);
    }
    
    scanf("%d %d %d", &S, &E, &Q);
    
    memset(dfn, -1, sizeof(dfn));
    dfs(-1, S);
    critic[S] = (nr_rad > 1);

    make_tree();
    memset(dfn, 0, sizeof(dfn));
    dfs_tree(1);
    
    x = find_vertex(S); y = find_vertex(E);
    find_path(x, y);

    from = 1; to = len_d;
    if (d[1] > NR_B) from++;
    if (d[len_d] > NR_B) to--;
    
    z = find_vertex(Q);    
    
    if (z != d[from] && z != d[to])
    { printf("No chance\n"); return 0; }
    
    if (z == d[to])
       reverse(d+from, d+to+1);

    d[from-1] = Q;  
    for (i = from; i <= to; i++)
        if (d[i] > NR_B)
           d[i] = V_NOD[d[i]][0];
 
    for (i = 1; i <= NR_B; i++)
        for (x = 0; x < card[i]; x++)
            for (y = 0; y < card[i]; y++)
            {
                a = V_NOD[i][x]; b = V_NOD[i][y];
                EM[i][x][y] = (ADIACENTA[a].find(b) != ADIACENTA[a].end());
            }
            
    d[from-1] = Q; d[to+1] = 0;
    for (i = from; i <= to; i+=2)
        if (d[i] <= NR_B)   
           add_small_path(d[i], d[i-1], d[i+1]);

    for (i = 1, x = 1; i < Res[0]; i++)
        if (Res[i] != Res[i+1])
           x++;
           
    printf("%d\n", x);    
    for (i = 1; i < Res[0]; i++)
        if (Res[i] != Res[i+1])
           printf("%d ", Res[i]);
    printf("%d\n", Res[Res[0]]);
    
    return 0;
}