#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
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) {
X[ind].push_back(indi[st[i]]);
++ Sol;
}
}
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]);
}