Cod sursa(job #1875425)

Utilizator RazvanR104Razvan-Andrei Ciocoiu RazvanR104 Data 11 februarie 2017 02:31:57
Problema Santa Scor 0
Compilator cpp Status done
Runda Lista lui wefgef Marime 4.67 kb
#include <bits/stdc++.h>

using namespace std;

const int NMAX = 50000, MMAX = 150000;
const int BMAX = 15;

int N, M;
int dfn[NMAX], low[NMAX];
bool isBridge[MMAX];
vector<pair<int, int>> G[NMAX], bridges;
vector<int> compNodes[NMAX], GB[NMAX][BMAX];
vector<tuple<int, int, int>> GC[NMAX];
int which[NMAX];
int S, E, Q;
int coresp[NMAX], invCoresp[NMAX][BMAX];
vector<int> answer;
bool DP[1 << BMAX][BMAX];
pair<int, int> fromDP[1 << BMAX][BMAX];

bool checkSimplePath(int source, int sink = -1) {
	vector<int> add;
	memset(DP, 0, sizeof DP);
	int compNum = which[source];
	int compSize = compNodes[compNum].size();
	source = coresp[source];
	if (sink != -1)
		sink = coresp[sink];
	DP[1 << source][source] = 1;
	fromDP[1 << source][source] = {-1, -1};
	for (int i = 0; i < (1 << compSize); ++i) {
		for (int j = 0; j < compSize; ++j)
			if (i & (1 << j)) {
				for (const int &it: GB[compNum][j]) {
					if (DP[i ^ (1 << j)][it]) {
						DP[i][j] = 1;
						fromDP[i][j] = {i ^ (1 << j), it};
						break;
					}
				}
			}
	}
	if (sink != -1 && DP[(1 << compSize) - 1][sink] == 0)
		return 0;
	int pos = sink;
	if (sink == -1) {
		for (int i = 0; i < compSize; ++i)
			if (DP[(1 << compSize) - 1][i]) {
				pos = i;
				break;
			}
		if (pos == -1)
			return 0;
	}
	int mask = (1 << compSize) - 1;
	do {
		add.push_back(invCoresp[compNum][pos]);
		tie(mask, pos) = fromDP[mask][pos];
	} while (mask != -1);
	for (int i = int(add.size()) - 1; i >= 0; --i)
		answer.push_back(add[i]);
	return 1;
}

void bridgeDFS(int node, int time) {
	dfn[node] = low[node] = time;
	for (const auto &it: G[node]) {
		if (!dfn[it.first]) {
			bridgeDFS(it.first, time + 1);
			low[node] = min(low[node], low[it.first]);
			if (low[it.first] >= dfn[node]) {
				isBridge[it.second] = 1;
				bridges.push_back({node, it.first});
			}
		} else
			low[node] = min(low[node], dfn[it.first]);
	}
}

void bridgeBFS(int node, int compNum) {
	queue<int> Q;
	Q.push(node);
	compNodes[compNum].push_back(node);
	which[node] = compNum;
	while (!Q.empty()) {
		int now = Q.front();
		Q.pop();
		for (const auto &it: G[now]) {
			if (isBridge[it.second] || which[it.first])
				continue;
			Q.push(it.first);
			compNodes[compNum].push_back(it.first);
			which[it.first] = compNum;
		}
	}
}

tuple<int, int, int> from[NMAX];
vector<int> path;
bool vis[NMAX];
void pathBFS(int source, int sink) {
	if (source == sink)
		return;
	queue<int> Q;
	Q.push(source);
	vis[source] = 1;
	bool continueSearch = 1;
	while (!Q.empty() && continueSearch) {
		int now = Q.front();
		Q.pop();
		for (const auto &it: GC[now]) {
			int to, x, y;
			tie(to, x, y) = it;
			if (vis[to])
				continue;
			Q.push(to);
			vis[to] = 1;
			from[to] = make_tuple(now, x, y);
			if (to == sink) {
				continueSearch = 0;
				break;
			}
		}
	}
	do {
		int to, x, y;
		tie(to, x, y) = from[sink];
		path.push_back(y);
		path.push_back(x);
		sink = to;
	} while (sink != source);
}

int main() {
	assert(freopen("santa.in", "r", stdin));
	assert(freopen("santa.out", "w", stdout));

	int i, j;
	scanf("%d %d", &N, &M);
	for (i = 1; i <= M; ++i) {
		int x, y;
		scanf("%d %d", &x, &y);
		G[x].push_back({y, i});
		G[y].push_back({x, i});
	}
	scanf("%d %d %d", &S, &E, &Q);

	bridgeDFS(1, 1);
	int currComp = 1;
	for (i = 1; i <= N; ++i)
		if (!which[i])
			bridgeBFS(i, currComp++);

	for (i = 1; i < currComp; ++i)
		assert(compNodes[i].size() <= 15);

	for (i = 1; i < currComp; ++i)
		for (j = 0; j < int(compNodes[i].size()); ++j) {
			coresp[compNodes[i][j]] = j;
			invCoresp[i][j] = compNodes[i][j];
		}

	for (i = 1; i < currComp; ++i) {
		for (const int &it: compNodes[i]) {
			for (const auto &next: G[it]) {
				if (which[it] != which[next.first])
					continue;
				GB[i][coresp[it]].push_back(coresp[next.first]);
				GB[i][coresp[next.first]].push_back(coresp[it]);
			}
		}
	}

	for (const auto &it: bridges) {
		int x, y;
		tie(x, y) = it;
		GC[which[x]].push_back(make_tuple(which[y], x, y));
		GC[which[y]].push_back(make_tuple(which[x], y, x));
	}

	if (which[Q] != which[S] && which[Q] != which[E]) {
		cout << "No chance\n";
		return 0;
	}

	if (which[Q] == which[S]) {
		path.push_back(Q);
		pathBFS(which[E], which[S]);
	} else {
		path.push_back(Q);
		pathBFS(which[S], which[E]);
	}

	for (i = 0; i + 1 < int(path.size()); ++i)
		if (!checkSimplePath(path[i], path[i + 1])) {
			cout << "No chance\n";
			return 0;
		}
	if (!checkSimplePath(path.back())) {
		cout << "No chance\n";
		return 0;
	}

	cout << answer.size() << '\n';
	for (const int &it: answer)
		cout << it << ' ';
	cout << '\n';
	return 0;
}