#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, int index_componenta)
{
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 ++)
if (*it == componente[index_componenta][Cod_Back[*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), index_componenta);
}
}
}
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], index_componenta);
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<N_Back; i++)
for (int j=0; j<(1<<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;
}