Cod sursa(job #1876203)

Utilizator RazvanR104Razvan-Andrei Ciocoiu RazvanR104 Data 12 februarie 2017 01:35:36
Problema Santa Scor 4
Compilator cpp Status done
Runda Lista lui wefgef Marime 3.76 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 onPath[NMAX];
vector<int> G[NMAX];
vector<int> GB[NMAX][BMAX];
vector<vector<int>> bcc;
int S, E, Q;
int invCoresp[NMAX][BMAX];
unordered_map<int, int> coresp[NMAX];
vector<int> answer;
bool DP[1 << BMAX][BMAX];
pair<int, int> fromDP[1 << BMAX][BMAX];

bool checkSimplePath(int source, int sink, int compNum) {
	vector<int> add;
	memset(DP, 0, sizeof DP);
	int compSize = bcc[compNum].size();
	source = coresp[compNum][source];
	if (sink != -1)
		sink = coresp[compNum][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: G[invCoresp[compNum][j]]) {
					if (!coresp[compNum].count(it))
						continue;
					int node = coresp[compNum][it];
					if (DP[i ^ (1 << j)][node]) {
						DP[i][j] = 1;
						fromDP[i][j] = {i ^ (1 << j), node};
						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;
}

stack<pair<int, int>> edges;
void cacheComponent(int x, int y) {
	int nowX, nowY;
	if (!onPath[y]) {
		do {
			tie(nowX, nowY) = edges.top();
			edges.pop();
		} while (nowX != x || nowY != y);
		return;
	}

	vector<int> currBcc;
	do {
		tie(nowX, nowY) = edges.top();
		edges.pop();
		currBcc.push_back(nowX);
		currBcc.push_back(nowY);
	} while (nowX != x || nowY != y);
	sort(currBcc.begin(), currBcc.end());
	currBcc.erase(unique(currBcc.begin(), currBcc.end()), currBcc.end());
	bcc.push_back(currBcc);
}

vector<int> path;
void biconnectedDFS(int node, int time) {
	dfn[node] = low[node] = time;
	for (const auto &it: G[node]) {
		if (!dfn[it]) {
			edges.push({node, it});
			biconnectedDFS(it, time + 1);
			onPath[node] |= onPath[it];
			low[node] = min(low[node], low[it]);
			if (low[it] >= dfn[node]) {
				cacheComponent(node, it);
				if (onPath[it] && time != 1)
					path.push_back(node);
			}
		} else
			low[node] = min(low[node], dfn[it]);
	}
}

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);
		G[y].push_back(x);
	}
	scanf("%d %d %d", &S, &E, &Q);

	onPath[S] = 1;
	biconnectedDFS(E, 1);
	reverse(path.begin(), path.end());

	if (find(bcc.front().begin(), bcc.front().end(), Q) == bcc.front().end()) {
		reverse(bcc.begin(), bcc.end());
		reverse(path.begin(), path.end());
	}
	if (find(bcc.front().begin(), bcc.front().end(), Q) == bcc.front().end()) {
		cout << "No chance\n";
		return 0;
	}

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

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

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