Cod sursa(job #1876238)

Utilizator RazvanR104Razvan-Andrei Ciocoiu RazvanR104 Data 12 februarie 2017 03:29:46
Problema Santa Scor 100
Compilator cpp Status done
Runda Arhiva de probleme Marime 3.59 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];
int coresp[NMAX];
int S, E, Q;
bool onPath[NMAX];
int DP[1 << BMAX][BMAX];
pair<int, int> toDP[1 << BMAX][BMAX];
vector<vector<int>> bcc;
vector<int> G[NMAX];
vector<int> answer;
vector<int> GC[BMAX];

void computeDP(int mask, int last, int size, int sink, int compNum) {
	if (DP[mask][last] != -1)
		return;
	if (mask == (1 << size) - 1) {
		toDP[mask][last] = {0, 0};
		DP[mask][last] = 0;
		if (last == sink || sink == -1)
			DP[mask][last] = 1;
		return;
	}
	DP[mask][last] = 0;
	for (const int &it: G[bcc[compNum][last]]) {
		int node = coresp[it];
		if (node == -1 || mask & (1 << node))
			continue;
		computeDP(mask ^ (1 << node), node, size, sink, compNum);
		if (DP[mask ^ (1 << node)][node]) {
			DP[mask][last] = 1;
			toDP[mask][last] = {mask ^ (1 << node), node};
			return;
		}
	}
}

bool checkSimplePath(int source, int sink, int compNum) {
	int compSize = bcc[compNum].size();
	for (int i = 0; i < int(bcc[compNum].size()); ++i)
		coresp[bcc[compNum][i]] = i;
	source = coresp[source];
	if (sink != -1)
		sink = coresp[sink];
	memset(DP, -1, sizeof DP);
	computeDP(1 << source, source, compSize, sink, compNum);
	for (int i = 0; i < int(bcc[compNum].size()); ++i)
		coresp[bcc[compNum][i]] = -1;
	if (DP[1 << source][source] == 0)
		return 0;
	int mask = 1 << source;
	int pos = source;
	do {
		answer.push_back(bcc[compNum][pos]);
		tie(mask, pos) = toDP[mask][pos];
	} while (mask);
	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;
	cin >> N >> M;
	for (i = 1; i <= M; ++i) {
		int x, y;
		cin >> x >> y;
		G[x].push_back(y);
		G[y].push_back(x);
	}
	cin >> S >> E >> Q;

	onPath[S] = 1;
	biconnectedDFS(E, 1);

	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;
	}

	path.insert(path.begin(), Q);
	memset(coresp, -1, sizeof coresp);
	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;
}