Cod sursa(job #2140089)

Utilizator oldatlantianSerban Cercelescu oldatlantian Data 23 februarie 2018 00:02:40
Problema ADN Scor 100
Compilator cpp Status done
Runda Arhiva de probleme Marime 2.61 kb
// long live automata theory and lambda calculus :}
#include <bits/stdc++.h>
using namespace std;

ifstream fi("adn.in");
ofstream fo("adn.out");

const int N = 18, M = 60005;

struct Edge {
	int v, cost; };

vector<Edge> g[N];
int state[M], dp[N][1 << N], anc[N][1 << N];

int n;
vector<int> links;
vector<string> v;

static int kmp(string &a, string &b) {
	string str = a + "#" + b;
	int n = str.size();

	memset(state, 0x00, 4 * n + 4);

	state[0] = -1;
	for (int p, i = 1; i < n; ++i) {
		p = state[i - 1];
		while (p >= 0 && str[p + 1] != str[i])
			p = state[p];

		if (str[p + 1] == str[i])
			p+= 1;

		state[i] = p; }

	return state[n - 1] + 1; }

static bool in(string a, string b) {
	int p, n = a.size(), m = b.size();

	memset(state, 0x00, 4 * a.size() + 4);

	state[0] = -1;
	for (int i = 1; i < a.size(); ++i) {
		p = state[i - 1];
		while (p >= 0 && a[p + 1] != a[i])
			p = state[p];

		if (a[p + 1] == a[i])
			p+= 1;

		state[i] = p; }

	p = -1;
	for (int i = 0; i < b.size(); ++i) {
		while (p >= 0 && (p + 1 >= a.size() || a[p + 1] != b[i]))
			p = state[p];

		if (a[p + 1] == b[i])
			p+= 1;

		if (p + 1 == a.size())
			return true; }

	return false; }

int main() {
	string str;
	int best, tmsk;

	fi >> n;
	v.resize(n);
	for (auto &i: v)
		fi >> i;

	sort(begin(v), end(v), [&](const string &a, const string &b) {
		return a.size() < b.size(); });

	for (int i = 0; i < n; ++i)
	for (int j = i + 1; j < n; ++j)
		if (in(v[i], v[j])) {
			v[i] = "";
			break; }

	partition(begin(v), end(v), [&](string &x) { return x != ""; });
	while (v.back() == "")
		v.pop_back();
	n = v.size();

	for (int i = 0; i < n; ++i)
	for (int j = 0; j < n; ++j) if (i != j)
		g[i].push_back({j, v[j].size() - kmp(v[j], v[i])});

	memset(dp, 0x3f, sizeof dp);
	for (int i = 0; i < n; ++i)
		dp[i][1 << i] = v[i].size();

	for (int msk = 1; msk < (1 << n); ++msk)
		for (int u = 0; u < n; ++u)
			for (auto v: g[u]) if ((~msk & (1 << v.v)) && dp[u][msk] + v.cost < dp[v.v][msk | (1 << v.v)]) {
				dp[v.v][msk | (1 << v.v)] = dp[u][msk] + v.cost;
				anc[v.v][msk | (1 << v.v)] = u; }

	best = 0, tmsk = (1 << n) - 1;
	for (int i = 1; i < n; ++i)
		if (dp[i][(1 << n) - 1] < dp[best][(1 << n) - 1])
			best = i;

	links.push_back(best);
	for (int t, i = 1; i < n; ++i) {
		t = best;

		best = anc[best][tmsk];
		tmsk^= 1 << t;
		links.push_back(best); }

	reverse(begin(links), end(links));
	best = links[0];
	str+= v[best];

	for (int i = 1; i < n; ++i) {
		for (auto l: g[best]) if (l.v == links[i]) {
			str+= string(begin(v[l.v]) + v[l.v].size() - l.cost , end(v[l.v]));
			break; }
		best = links[i]; }

	fo << str << endl;
	cerr << str.size() << endl;

	return 0; }