Cod sursa(job #34690)

Utilizator m_dersidanDersidan Mihai m_dersidan Data 21 martie 2007 10:54:52
Problema ADN Scor 50
Compilator cpp Status done
Runda Arhiva de probleme Marime 2.24 kb
# include <stdio.h>
# include <string.h>

# define  _fin  "adn.in"
# define  _fout "adn.out"

# define  maxn	20
# define  maxw	30004
# define  pow2n 262244


int c[maxn][maxn], out[maxn], n,
	a[maxn][pow2n], sol[maxn],
	p[maxn][maxw], f[maxn][pow2n];

char w[maxn][maxw];

void readf()
{
	freopen(_fin, "r", stdin);
	scanf("%d\n", &n);
	for (int i=1; i<=n; i++)
		scanf("%s\n", w[i]+1), w[i][0]='0';
//		memmove(w[i]+1, w[i], sizeof(w[i])), w[i][0]='0';
}

int kmp(int a, int b, int &match)
{
	int k=0, i, to=strlen(w[a]);
	
	for (i=1; i<to; i++)
	{
		while ( k>0 && w[b][k+1] != w[a][i] ) k=p[b][k];
		k += ( w[b][k+1]==w[a][i] );
		if ( k==strlen(w[b])-1 ) {
			match=strlen(w[b])-1;
			return 1;
		}
	}
	match=k;
	
	return 0;
}

void presolve()
{
	// precalculate N and C
	int i, j, k, foo, to;
	
	// calculate pi for all
	for (j=1; j<=n; j++)
		for (i=2, k=0, to=strlen(w[j]); i<to; i++)
		{
			while ( k>0 && w[j][k+1] != w[j][i] ) k=p[j][k];
			k += ( w[j][k+1]==w[j][i] );
			p[j][i]=k;
		}

	
	// first, take out all words that we don't need
	for (i=1; i<=n; i++)
		for (j=1; j<=n; j++)
		{
			if ( i==j ) continue;
			if ( kmp(i, j, foo) )
				out[j]=1;
		}

	for (i=n; i>=1; i--)
		if ( out[i] )
			memcpy(w[i], w[n], sizeof(w[n])), n--;

	for (i=1; i<=n; i++)
		for (j=1; j<=n; j++)
		{
			if ( i==j ) continue;
			kmp(i, j, c[i][j]);
		}
}

void solve()
{
	int i, j, k, l, to=(1<<n)-1, pw;
	
	memset(a, 0xff, sizeof(a));
	for (i=1; i<=n; i++) a[i][1<<(i-1)]=0;
	
	for (i=3; i<=to; i++)
		for (j=1, pw=1; j<=n; j++, pw<<=1)
		{
			if ( !(i & pw) ) continue;
			
			for (k=1; k<=n; k++)
				if ( i & (1<<(k-1)) )
					if ( c[j][k] + a[k][ i ^ pw ] > a[j][i] )
						a[j][i] = c[j][k] + a[k][i^pw], f[j][i]=k;
		}
	
	int max=1;
	for (i=2; i<=n; i++)
		if ( a[i][to] > a[max][to] ) max=i;
	
	for (i=max, j=to; f[i][j] && sol[0] < n; k=i, i=f[i][j], j^=(1<<(k-1)))
		sol[ ++sol[0] ] = i;
	sol[ ++sol[0] ] = i;
}

void writef()
{
	freopen(_fout, "w", stdout);
	int i;
	for (printf("%s", w[sol[1]]+1), i=2; i<=sol[0]; i++)
		 printf("%s", w[sol[i]] + c[sol[i-1]][sol[i]]+1);
	
	printf("\n");
}

int main()
{
	readf();
	presolve();
	solve();
	writef();

	return 0;
}