Cod sursa(job #773500)

Utilizator vlad.maneaVlad Manea vlad.manea Data 1 august 2012 21:16:12
Problema ADN Scor 100
Compilator cpp Status done
Runda Arhiva de probleme Marime 3.91 kb
#include <fstream>
#include <string>
#include <climits>
#include <algorithm>

#define INFILE "adn.in"
#define OUTFILE "adn.out"
#define NMAX 18
#define SMAX 30001
#define EMAX 262999

using namespace std;

int N;
string S[SMAX];
int Size[NMAX];
bool L[NMAX];
int Mch[NMAX][NMAX];
int Min[NMAX][EMAX];
int Whi[NMAX][EMAX];

void computePrefix(string S, int size, int Pi[])
{
	int i, k;

	for (i = 1; i <= size; ++i)
	{
		Pi[i] = 0;
	}

	// functia prefix
	for (i = 2; i <= size; ++i)
	{
		k = Pi[i - 1];

		while (k > 0 && S[k + 1] != S[i])
		{
			k = Pi[k];
		}

		if (S[k + 1] == S[i])
		{
			++k;
		}

		Pi[i] = k;
	}
}

bool getMatch(string T, int Tsize, string X, int Xsize, int Pi[])
{
	int i, k;

	// functia potrivire
	for (i = 1, k = 0; i <= Tsize; ++i)
	{
		while (k > 0 && X[k + 1] != T[i])
		{
			k = Pi[k];
		}

		if (X[k + 1] == T[i])
		{
			++k;
		}

		if (k == Xsize)
		{
			return true;
		}
	}

	return false;
}

bool firstContainsSecond(int t, int x)
{
	if (Size[t] < Size[x])
	{
		return false;
	}

	int i, k;
	int Pi[SMAX];

	computePrefix(S[x], Size[x], Pi);

	return getMatch(S[t], Size[t], S[x], Size[x], Pi);
}

int computePrefixSuffix(int x, int y)
{
	string T = " " + S[x].substr(1, Size[x]) + S[y].substr(1, Size[y]);
	int Tsize = Size[x] + Size[y];

	int i, k;
	int Pi[SMAX + SMAX];

	computePrefix(T, Tsize, Pi);

	int mini = min(Size[x], Size[y]);

	while (Pi[Tsize] > mini)
	{
		Tsize = Pi[Tsize];
	}

	return Pi[Tsize];
}

void eliminateInclusions()
{
	int i, j;

	for (i = 0; i < N; ++i)
	{
		for (j = 0; j < N; ++j)
		{
			if (i == j)
			{
				continue;
			}

			if (firstContainsSecond(j, i))
			{
				if (Size[j] != Size[i] || i < j)
				{
					L[i] = true;
				}
			}
		}
	}

	for (i = j = 0; i < N && j < N; ++i, ++j)
	{
		while (L[j])
		{
			++j;
		}

		S[i] = S[j];
		Size[i] = Size[j];
	}

	N = i;
}

void computePrefixesSuffixes()
{
	int i, j;

	for (i = 0; i < N; ++i)
	{
		for (j = 0; j < N; ++j)
		{
			if (i == j)
			{
				continue;
			}

			Mch[i][j] = computePrefixSuffix(i, j);
		}
	}
}

void computeHamiltonians()
{
	int i, j, k, l, v;

	// Do the steps for singular words
	for (i = 0; i < N; ++i)
	{
		Min[i][1 << i] = Size[i];
		Whi[i][1 << i] = INT_MAX;
	}

	// Do the steps for bigger numbers
	for (k = 1; k < (1 << N); ++k)
	{
		for (i = 0; i < N; ++i)
		{
			if (!(k ^ (1 << i)))
			{
				continue;
			}

			Min[i][k] = Whi[i][k] = INT_MAX;

			if (!(k & (1 << i)))
			{
				continue;
			}

			l = k ^ (1 << i);

			for (j = 0; j < N; ++j)
			{
				if (i == j || !(k & (1 << j)))
				{
					continue;
				}

				v = Min[j][l] + Size[i] - Mch[i][j];
				
				if (v < Min[i][k])
				{
					Min[i][k] = v;
					Whi[i][k] = j;
				}
			}
		}
	}
}

string computeMinString()
{
	int i, j, k;
	string T = "";
	int min = INT_MAX;
	int sta = INT_MAX;

	for (i = 0; i < N; ++i)
	{
		if (Min[i][(1 << N) - 1] < min)
		{
			min = Min[i][(1 << N) - 1];
			sta = i;
		}
	}

	for (i = sta, k = (1 << N) - 1; i != INT_MAX; k = k ^ (1 << i), i = j)
	{
		j = Whi[i][k];

		if (j == INT_MAX)
		{
			T = T + S[i];
		}
		else
		{
			T = T + S[i].substr(0, Size[i] - Mch[i][j]);
		}
	}

	std::reverse(T.begin(), T.end());
	return T;
}

void readWords()
{
	int i;
	ifstream fin(INFILE);
	fin >> N;

	for (i = 0; i < N; ++i)
	{
		fin >> S[i];
		Size[i] = S[i].size();
		S[i] = " " + S[i];
	}

	fin.close();
}

void writeConcatenation()
{
	int i;

	for (i = 0; i < N; ++i)
	{
		S[i] = S[i].substr(1, Size[i]);
		std::reverse(S[i].begin(), S[i].end());
	}

	ofstream fout(OUTFILE);
	fout << computeMinString() << endl;
	fout.close();
}

int main()
{
	readWords();

	eliminateInclusions();

	computePrefixesSuffixes();

	computeHamiltonians();

	writeConcatenation();

	return 0;
}