Cod sursa(job #683404)

Utilizator mihaipopa12Popa Mihai mihaipopa12 Data 20 februarie 2012 16:33:25
Problema ADN Scor 100
Compilator cpp Status done
Runda Arhiva de probleme Marime 2.87 kb
#include<stdio.h>
#include<cstring>
#include<cstdlib>

#define maxn 20
#define maxdim 30005

FILE*f=fopen("adn.in","r");
FILE*g=fopen("adn.out","w");

const int INF = (1<<29);

int n,last;
int pi[maxdim],D[maxn][maxn],Len[maxn],Best[maxn-1][1<<(maxn-2)],T[maxn-1][1<<(maxn-2)];
char A[maxn][maxdim];

inline void citire () {
	
	fscanf(f,"%d",&n);
	
	for ( int i = 1 ; i <= n ; ++i ){
		fscanf(f,"%s",A[i]+1);
		Len[i] = strlen(A[i]+1);
	}
}

inline void prefix ( char *A , int n ){
	
	int k = 0;
	for ( int i = 2 ; i <= n ; ++i ){
		
		while ( k > 0 && A[k+1] != A[i] ){
			k = pi[k];
		}
		if ( A[k+1] == A[i] ){
			k = k + 1;
		}
		
		pi[i] = k;
	}
}

inline int kmp ( char *A , int n , char *B , int m ){
	
	int q = 0;
	for ( int i = 1 ; i <= m ; ++i ){
		
		while ( q > 0 && A[q+1] != B[i] ){
			q = pi[q];
		}
		if ( A[q+1] == B[i] ){
			q = q + 1;
		}
		
		if ( q == n ){
			return -1;
		}
	}
	
	return q;
}

inline void calculeaza () {
	
	for ( int i = 1 ; i <= n ; ++i ){
		prefix(A[i],Len[i]);
		for ( int j = 1 ; j <= n ; ++j ){
			if ( i != j ){
				if ( kmp(A[i],Len[i],A[j],Len[j]) == -1 ){
					memcpy(A[i],A[n],sizeof(A[n])); Len[i] = Len[n];
					memset(A[n],0,sizeof(0));
					--n; --i;
					break ;
				}
			}
		}
	}
	
	if ( n == 1 ){
		fprintf(g,"%s\n",A[1]+1);
		fclose(f); fclose(g);
		exit(0);
	}
	
	for ( int i = 1 ; i <= n ; ++i ){
		D[0][i] = Len[i];
		prefix(A[i],Len[i]);
		for ( int j = 1 ; j <= n ; ++j ){
			if ( i != j ){
				D[j][i] = kmp(A[i],Len[i],A[j],Len[j]);
			}
		}
	}
	
	for ( int i = 1 ; i <= n ; ++i ){
		for ( int j = 1 ; j <= n ; ++j ){
			if ( i != j ){
				D[i][j] = Len[j] - D[i][j];
			}
		}
	}
}

inline void solve () {
	
	for ( int i = 1 ; i < (1<<n) ; ++i ){
		for ( int j = 1 ; j <= n ; ++j ){
			Best[j][i] = INF;
			T[j][i] = -1;
		}
	}
	
	for ( int i = 1 ; i <= n ; ++i ){
		Best[i][1<<(i-1)] = D[0][i];
	}
	
	for ( int i = 1 ; i < (1<<n) ; ++i ){
		for ( int j = 1 ; j <= n ; ++j ){
			if ( Best[j][i] != INF )	continue ;
			int b1 = j - 1;
			if ( i & (1<<b1) ){
				for ( int k = 1 ; k <= n ; ++k ){
					int b2 = k - 1;
					if ( b1 != b2 && (i & (1<<b2)) ){
						if ( Best[k][i^(1<<b1)] + D[k][j] < Best[j][i] ){
							Best[j][i] = Best[k][i^(1<<b1)] + D[k][j];
							T[j][i] = b2;
						}
					}
				}
			}
		}
	}
	
	last = 1;
	for ( int i = 2 ; i <= n ; ++i ){
		if ( Best[i][(1<<n)-1] < Best[last][(1<<n)-1] ){
			last = i;
		}			
	}
}

void print ( int conf , int bit ){
	if ( !conf ){
		return ;
	}
	
	int nr = D[T[bit+1][conf]+1][bit+1];
	print(conf^(1<<bit),T[bit+1][conf]);
	int cuv = bit + 1;
	fprintf(g,"%s",A[cuv]+Len[cuv]-nr+1);
	if ( conf == (1<<n)-1 )
		fprintf(g,"\n");
}

int main () {
	
	citire();
	calculeaza();
	solve();
	print((1<<n)-1,last-1);
	
	fclose(f);
	fclose(g);
	
	return 0;
}