Cod sursa(job #1876232)

Utilizator RazvanR104Razvan-Andrei Ciocoiu RazvanR104 Data 12 februarie 2017 03:06:38
Problema Santa Scor 30
Compilator cpp Status done
Runda Lista lui wefgef Marime 4.45 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;

const int BUFFER_SIZE = 1 << 20;
class Reader {
public:
	Reader() {}
	Reader(const char* filename) {
		file = fopen(filename, "r");
		cursor = 0;
		fread(buffer, BUFFER_SIZE, 1, file);
	}
	inline Reader & operator >> (int &n) {
		n = 0;
		while(!isdigit(buffer[cursor])) {
			advance();
		}
		while(isdigit(buffer[cursor])) {
			n = n * 10 + buffer[cursor] - '0';
			advance();
		}
		return *this;
	}

	inline void close() {
		fclose(file);
	}
private:
	int cursor, sign;
	char buffer[BUFFER_SIZE];
	FILE* file;
	inline void advance() {
		++cursor;
		if(cursor == BUFFER_SIZE) {
			cursor = 0;
			fread(buffer, BUFFER_SIZE, 1, file);
		}
	}
};

vector<int> GC[BMAX];
void computeDP(int mask, int last, int size, int sink) {
	if (DP[mask][last] != -1)
		return;
	if (mask == (1 << size) - 1) {
		DP[mask][last] = 0;
		if (last == sink || sink == -1)
			DP[mask][last] = 1;
		return;
	}
	DP[mask][last] = 0;
	for (const int &it: GC[last]) {
		if (mask & (1 << it))
			continue;
		computeDP(mask ^ (1 << it), it, size, sink);
		if (DP[mask ^ (1 << it)][it]) {
			DP[mask][last] = 1;
			toDP[mask][last] = {mask ^ (1 << it), it};
			return;
		}
	}
}

bool checkSimplePath(int source, int sink, int compNum) {
	int compSize = bcc[compNum].size();
	for (int i = 0; i < compSize; ++i)
		GC[i].clear();

	for (int i = 0; i < int(bcc[compNum].size()); ++i)
		coresp[bcc[compNum][i]] = i;
	for (const int &vertex: bcc[compNum]) {
		for (const int &next: G[vertex]) {
			if (coresp[next] == -1)
				continue;
			GC[coresp[vertex]].push_back(coresp[next]);
			GC[coresp[next]].push_back(coresp[vertex]);
		}
	}

	source = coresp[source];
	if (sink != -1)
		sink = coresp[sink];

	memset(DP, -1, sizeof DP);
	computeDP(1 << source, source, compSize, sink);

	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;
	Reader cin("santa.in");
	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;
	}

	printf("%d\n", answer.size());
	for (const int &it: answer)
		printf("%d ", it);
	printf("\n");
	return 0;
}