Cod sursa(job #1483693)

Utilizator tamionvTamio Vesa Nakajima tamionv Data 9 septembrie 2015 19:27:47
Problema ADN Scor 50
Compilator cpp Status done
Runda Arhiva de probleme Marime 3.23 kb
#include <fstream>
#include <string>
#include <vector>
#include <algorithm>
#include <functional>
using namespace std;

int longest_common_pref_suf(const string& a, const string& b){
	const string s = b + "#" + a;
	const int n = s.size();
	vector<int> v(n, 0);
	for(int i = 1; i < n; ++i){
		int j = v[i-1];
		for( ;
			j > 0 && s[j] != s[i];
			j = v[j-1]);
		if(s[j] == s[i]){
			++j; }
		v[i] = j; }
	return v.back(); }

bool apartine(const string& mic, const string& mare){
	const string s = mic + "#" + mare;
	const int n = s.size();
	vector<int> v(n, 0);
	for(int i = 1; i < n; ++i){
		int j = v[i-1];
		for( ;
			j > 0 && s[j] != s[i];
			j = v[j-1]);
		if(s[j] == s[i]){
			++j; }
		v[i] = j; }
	return any_of(begin(v)+mic.size()+1, end(v), [mic](const int x){
		return x == mic.size(); }); }

void make_graf(const vector<string>& v, vector<vector<int> >& graf){
	const int n = v.size();
	graf.resize(n, vector<int>(n, 0));
	for(int i = 0; i < n; ++i){
		for(int j = 0; j < n; ++j){
			if(i != j){
				const int len = v[j].size() - longest_common_pref_suf(v[i], v[j]);
				graf[i][j] = len; } } } }

void backtrack(const vector<vector<int> >& graf, vector<vector<int> >& cost,
	vector<vector<int> >& prev, vector<int>& cur, const int cod_cur, const int sz){
	if(sz == cur.size()){
		for(const auto x : cur){
			for(const auto y : cur){
				if(y != x && cost[x][cod_cur] > cost[y][cod_cur ^ (1<<x)] + graf[y][x]){
					cost[x][cod_cur] = cost[y][cod_cur ^ (1<<x)] + graf[y][x];
					prev[x][cod_cur] = y; } } } }
	else{
		for(int next = cur.back() + 1; next < graf.size(); ++next){
			cur.push_back(next);
			backtrack(graf, cost, prev, cur, cod_cur | (1<<next), sz);
			cur.pop_back(); } } }

void hamiltonian_path(const vector<vector<int> >& graf, const int st, vector<int>& rez){
	const int n = graf.size();
	vector<vector<int> > cost(n, vector<int>(1<<n, 1e8)),
		prev(n, vector<int>(1<<n, 0));
	cost[st][1<<st] = 0;
	prev[st][1<<st] = st;
	vector<int> cur = {st};

	for(int sz = 2; sz <= n; ++sz){
		backtrack(graf, cost, prev, cur, 1<<st, sz); }

	const int all_one = (1<<n) - 1;
	int fin_coord = -1, cost_min = 1e9;

	for(int i = 0; i < n; ++i){
		if(cost_min > cost[i][all_one]){
			cost_min = cost[i][all_one];
			fin_coord = i; } }

	for(int i = fin_coord, cod = all_one; i != st; ){
		rez.push_back(i);
		const int cod_n = cod ^ (1<<i);
		i = prev[i][cod];
		cod = cod_n; }
	rez.push_back(st);
	reverse(begin(rez), end(rez)); }

void citeste_strings(ifstream& f, vector<string>& v){
	int n = 0;
	f >> n;
	v.resize(n+1);
	for(int i = 1; i <= n; ++i){
		f >> v[i]; }

	vector<int> to_erase;
	
	for(int i = 1; i < v.size(); ++i){
		for(int j = 1; j < v.size(); ++j){
			if(i != j && v[i].size() <= v[j].size() && apartine(v[i], v[j])){
				to_erase.push_back(i); } } }

	sort(begin(to_erase), end(to_erase), greater<int>());

	for(const auto x : to_erase){
		v.erase(begin(v) + x); } }

int main(){
	ifstream f("adn.in");
	ofstream g("adn.out");
	vector<string> v;
	citeste_strings(f, v);

	vector<vector<int> > graf;
	make_graf(v, graf);

	vector<int> rez;
	hamiltonian_path(graf, 0, rez);
	for(int i = 0; i < rez.size()-1; ++i){
		const int a = rez[i], b = rez[i+1];
		const int lung = graf[a][b];
		for(int i = v[b].size() - lung; i < v[b].size(); ++i){
			g << v[b][i]; } }
	return 0; }