#include <cstdio>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;
#define MAXN 45005
int N, M;
int S, D, Qs;
vector<int> con[MAXN];
int alt[MAXN], p[MAXN], low[MAXN], art[MAXN], u[MAXN];
vector<int> nodincomp[MAXN];
vector< vector<int> > compnod;
vector< vector< pair<int, int> > > compmuc;
vector<bool> usecomp, usenod;
vector< pair<int, int> > st;
/*
* introduce muchia (a, b) in stiva
*/
void push(int a, int b) { st.push_back( make_pair(a, b) ); }
/*
* extrage componenta biconexa
* scoate muchii din stiva pana ajunge la (a, b)
*/
void popcomp(int a, int b)
{
vector<int> noduri;
vector< pair<int, int> > muchii;
noduri.clear(); muchii.clear();
for (; 1; st.pop_back())
{
noduri.push_back( st.back().first );
noduri.push_back( st.back().second );
muchii.push_back( st.back() );
if ( st.back() == make_pair(a, b) )
{
st.pop_back();
break;
}
}
sort(noduri.begin(), noduri.end());
sort(muchii.begin(), muchii.end());
noduri.resize( unique(noduri.begin(), noduri.end()) - noduri.begin() );
muchii.resize( unique(muchii.begin(), muchii.end()) - muchii.begin() );
compnod.push_back( noduri );
compmuc.push_back( muchii );
usecomp.push_back( false ); //aflu mai tarziu daca componenta respectiva e pe drumu piticilor :)
//drumul piticilor va fi un sir de componente biconexe si puncte de articulatie
//fiecare punct de articulatie va aparea doar o data in drum si astfel se va trece
//prin maxim 2 componente biconexe legate de orice punct de articulatie
for (size_t i = 0; i < noduri.size(); i++)
nodincomp[ noduri[i] ].push_back( (int)compnod.size() - 1 );
}
/*
* afla componentele biconexe
*/
void dfs(int k)
{
int NCHILD = 0; //numarul de fii in arborele DF al nodului curent, util sa vad daca nodu 1 e critic
u[k] = 1;
low[k] = alt[k];
vector<int> :: iterator it;
for (it = con[k].begin(); it != con[k].end(); it++)
{
if (!u[*it])
{
alt[*it] = alt[k] + 1;
p[*it] = k;
push(k, *it);
dfs(*it);
NCHILD++;
if (low[*it] < low[k])
low[k] = low[*it];
if (low[*it] >= alt[k]) //nodul k e critic
{
art[k] = 1;
if (k == 1 && NCHILD < 2)
art[k] = 0;
popcomp(k, *it); //extrage componenta biconexa
}
}
else
if (*it != p[k] && alt[*it] < alt[k])
{
push(k, *it);
if (alt[*it] < low[k])
low[k] = alt[*it];
}
}
}
/*
* marcheaza componenta biconexa (cur) ca facand parte dintr-un potential drum al piticilor
*/
inline void MARK(int cur)
{
vector< int > :: iterator it;
usecomp[cur] = true;
for (it = compnod[cur].begin(); it != compnod[cur].end(); it++)
usenod[*it] = true;
}
/*
* marcheaza nodurile ce trebuie vizitate
*/
queue<int> Q;
int START, END; //prima si ultima componenta biconexa din drumul piticilor
vector< bool > hasS, hasD, hasQs;
int bfs(int S)
{
for (; !Q.empty(); Q.pop());
int i;
vector< int > :: iterator it;
memset(u, -1, sizeof(u)); //in u voi mentine componenta biconexa precedenta
memset(p, -1, sizeof(p)); //in p voi mentine nodul critic care leaga componenta biconexa curenta de cea precedenta
usenod.clear(); usenod.resize(N + 1, false);
//gasesc pentru toate componentele biconexe daca contin cele 3 noduri importante :)
hasS.resize( compnod.size(), false );
hasD.resize( compnod.size(), false );
hasQs.resize( compnod.size(), false );
for (size_t k = 0; k < compnod.size(); k++)
for (size_t a = 0; a < compnod[k].size(); a++)
{
if (compnod[k][a] == S) hasS[k] = true;
if (compnod[k][a] == D) hasD[k] = true;
if (compnod[k][a] == Qs) hasQs[k] = true;
}
//gasesc componenta biconexa din care va incepe drumul (cea care contine Qs
//pentru a avea solutie trebuie ca Qs sa se afla in aceeasi componenta biconexa cu S sau cu D
START = -1;
for (size_t k = 0; k < compnod.size(); k++)
if ((hasS[k] && hasQs[k]) || (hasD[k] && hasQs[k]))
{
START = k;
break;
}
if (START == -1)
return 0;
int foundS, foundD;
foundS = hasS[START] ? 1 : 0;
foundD = hasD[START] ? 1 : 0;
if (foundS && foundD)
{
END = START;
MARK(START);
return 1;
}
//bfs
for (Q.push(START), u[START] = START; !Q.empty() && (!foundS || !foundD); Q.pop())
{
i = Q.front();
for (size_t k = 0; k < compnod[i].size(); k++)
{
int n = compnod[i][k];
for (it = nodincomp[n].begin(); it != nodincomp[n].end(); it++)
{
if (u[*it] != -1)
continue;
u[*it] = i;
p[*it] = n;
Q.push( *it );
//verific daca am gasit componenta biconexa cu care se incheie drumul
if (!foundD && hasD[*it])
{
END = *it;
foundD = 1;
break;
}
if (!foundS && hasS[*it])
{
END = *it;
foundS = 1;
break;
}
}
}
}
if (!foundS || !foundD)
return 0;
//marchez nodurile care vor face parte din drum
for (i = END; i != START; i = u[i])
MARK(i);
MARK(START);
return 1;
}
vector<int> DRUM; //solutia problemei
/*
* genereaza drumul pentru o componenta biconexa
*/
int stb[MAXN];
int back(int comp, int last, int k)
{
int i;
if (k == (int)compnod[comp].size() - 1)
{
if (stb[k] == last || last == -1)
{
for (i = 1; i <= k; i++)
DRUM.push_back( stb[i] );
return 1;
}
return 0;
}
int cur = stb[k];
for (i = 0; i < (int)compmuc[comp].size(); i++)
{
pair<int, int> muc = compmuc[comp][i];
if (muc.first != cur && muc.second != cur)
continue;
int nxt = muc.first + muc.second - cur;
if (u[nxt])
continue;
u[nxt] = 1;
stb[k + 1] = nxt;
if (back(comp, last, k + 1))
return 1;
u[nxt] = 0;
}
return 0;
}
/*
* genereaza drumul cerut
*/
void makedrum()
{
vector<int> dr; //drumul format din componente biconexe
vector<int> snod; //nodul din care incepe drumul hamiltonian in componenta curenta
int i;
for (i = END; i != START; i = u[i])
dr.push_back( i ),
snod.push_back( p[i] );
dr.push_back( START );
snod.push_back( Qs );
reverse( dr.begin(), dr.end() );
reverse( snod.begin(), snod.end() );
DRUM.push_back( snod[0] );
for (i = 0; i < (int)dr.size() - 1; i++)
{
memset(u, 0, sizeof(u)); //reset used nodes
stb[0] = snod[i];
back(dr[i], snod[i + 1], 0); //ar fi mers dinamica memoizata
}
stb[0] = snod[i];
back(dr[i], -1, 0);
for (i = 0; i < (int)DRUM.size(); i++)
printf("%d ", DRUM[i]);
printf("\n");
}
int main()
{
freopen("santa.in", "rt", stdin);
freopen("santa.out", "wt", stdout);
scanf("%d %d", &N, &M);
for (; M; M--)
{
int i, j;
scanf("%d %d", &i, &j);
con[i].push_back(j);
con[j].push_back(i);
}
scanf("%d %d %d", &S, &D, &Qs);
dfs(1); //afla componentele biconexe
if (!bfs(S)) //afla toate nodurile care trebuie atinse
{
printf("No chance\n");
return 0;
}
int NR = 0;
for (int i = 1; i <= N; i++)
if (usenod[i])
NR++;
printf("%d\n", NR);
makedrum();
return 0;
}