Cod sursa(job #1024255)

Utilizator scipianusFMI Ciprian Olariu scipianus Data 8 noiembrie 2013 14:53:19
Problema ADN Scor 40
Compilator cpp Status done
Runda Arhiva de probleme Marime 3.31 kb
#include <fstream>
#include <cstring>
#include <algorithm>
using namespace std;
int n, Pi[30100], ns[20], cost[20][20], best[18][263000], Next[18][263000], sol;
char s[20][30100];
bool eliminat[20];
string S[20];

inline void CreateGraph()
{
	int i, j, k, p;
	// elimin cuvintele incluse in alte cuvinte
	for( i = 0; i < n; ++i)
	{
		for( j = i + 1; j < n && !eliminat[i]; ++j)
		{
			memset(Pi, 0, sizeof(Pi));
			Pi[1] = 0;
			k = 0;
			for( p = 2; p <= ns[i]; ++p)
			{
				while( k && s[i][k + 1] != s[i][p]) k = Pi[k];
				if(s[i][k + 1] == s[i][p]) k++;
				Pi[p] = k;
			}
			k = 0;
			for( p = 1; p <= ns[j]; ++p)
			{
				while(k && s[i][k + 1] != s[j][p]) k=Pi[k];
				if(s[i][k + 1] == s[j][p]) k++; 
				if(k == ns[i])
				{
					eliminat[i]=true;
					p=ns[j];
				}
			}
		}
	}
	// calculez cel mai lung sufix al unui cuvant care este prefix al altuia
	for( i = 0; i < n; ++i)
	{
		if(eliminat[i])
			continue;
		for( j = 0; j < n; ++j)
		{
			if(eliminat[j])
				continue;
			memset(Pi, 0, sizeof(Pi));
			Pi[1] = 0;
			k = 0;
			for( p = 2; p <= ns[i]; ++p)
			{
				while( k && s[j][k + 1] != s[i][p]) k = Pi[k];
				if(s[j][k + 1] == s[i][p]) k++;
				Pi[p] = k;
			}
			cost[i][j] = Pi[ns[i]];
		}
	}
	
}

inline string FindCycle()
{
	int i, j, conf, first, aux, conflim = 0;
	string rez;
	// initializez matricea cu INF
	for( conf = 0; conf < (1<<n); ++conf)
		for( i = 0; i < n; ++i)
			best[i][conf] = 1000000000;
	// asta va fi configuratia finala
	for( i = 0; i < n; ++i)
		if(!eliminat[i])
			conflim += (1 << i);
	// initializez starile initiale
	for( i = 0; i < n; ++i)
		best[i][( 1 << i)] = ns[i];
	// fac dinamica pentru lant hamiltonian de cost minim
	for( conf = 0; conf < (1<<n); ++conf)
	{
		for( i = 0; i < n; ++i)
		{
			if(eliminat[i])
				continue;
			if(conf & (1 << i))
			{
				for( j = 0; j < n; ++j)
				{
					if(eliminat[j])
						continue;
					if(!(conf & (1 << j)))
					{
						if(best[j][conf + (1 << j)] > ns[j] - cost[j][i] + best[i][conf])
						{
							best[j][conf + (1 << j)] = ns[j] - cost[j][i] + best[i][conf];
							Next[j][conf + (1 << j)] = i;
						}
					}
				}
			}
		}
	}
	// determin nodul de start din lant
	first = -1;
	sol = 1000000000;
	for( i = 0; i < n; ++i)
	{
		if(eliminat[i])
			continue;
		if(best[i][conflim] < sol)
		{
			sol = best[i][conflim];
			first = i;
		}
	}
	// construiesc secventa ADN care va fi solutie
	for( i = 1; i <= ns[first]; ++i)
		rez += s[first][i];
	conf = conflim;
	while(Next[first][conf])
	{
		aux = first;
		first = Next[first][conf];
		conf -= (1 << aux);
		for( i = cost[aux][first] + 1; i <= ns[first]; ++i)
			rez += s[first][i];
	}
	return rez;
}

inline bool Sortare(string a, string b)
{
	if(a.size() < b.size())
		return true;
	if(a.size() > b.size())
		return false;
	if(a.compare(b)<=0)
		return true;
	return false;
}

int main()
{
	int i, j;
	ifstream fin("adn.in");
	fin >> n;
	for(i = 0; i < n; ++i)
		fin >> S[i];
	fin.close();
	
	// sortez sirurile lexicografic 
	sort(S, S + n, Sortare);
	for(i = 0; i < n; ++i)
	{
		ns[i] = S[i].size();
		for(j = 0; j < ns[i]; ++j)
			s[i][j + 1]= S[i][j];
	}
	CreateGraph();
	
	ofstream fout("adn.out");
	fout << FindCycle() << "\n";
	fout.close();
	return 0;
}