Cod sursa(job #311236)

Utilizator sima_cotizoSima Cotizo sima_cotizo Data 3 mai 2009 00:26:32
Problema ADN Scor 100
Compilator cpp Status done
Runda Arhiva de probleme Marime 2.21 kb
#include <fstream>
#include <iostream>
#include <cstring>
#include <queue>
using namespace std;
#define MAXN 18
#define MAXL 30010
#define MASK (1<<MAXN)
ifstream in("adn.in");
ofstream out("adn.out");

char C[MAXN][MAXL];
int L[MAXN], N, i, M;
int G[MAXN][MAXN], tmp[MAXN];
int pi[MAXL];
bool Disabled[MAXN];
bool Used[MASK];
int A[MAXN][MASK];
char Last[MAXN][MASK];
queue<int> Q;

void back_print(int n, int mask) {
	cerr << n << " " << mask << "\n";
	if ( (mask&(-mask)) == mask ) {
		for (int i=1; i<=L[n]; ++i)
			out << C[n][i];
		return;
	}
	int l = Last[n][mask];
	back_print(l, mask-(1<<n));
	for (int i=G[l][n]+1; i<=L[n]; ++i)
		out << C[n][i];
}

int main() {
	in >> N;
	char c_tmp;
	in.get(c_tmp);
	for (i=0; i<N; ++i) {
		in.getline(C[i]+1, MAXL-1);
		for (L[i]=strlen(C[i]+1); C[i][L[i]]>'T' || C[i][L[i]]<'A'; --L[i])
			C[i][L[i]] = 0;
	}

	// preprocesare suprapuneri O(N^2*L)
	for (i=0; i<N; ++i) {
		int k=0, j, t;
		pi[1] = 0;
		for (j=2; j<=L[i]; ++j) {
			while (C[i][j]!=C[i][k+1] && k) k=pi[k];
			if (C[i][j]==C[i][k+1]) ++k;
			pi[j] = k;
		}
		for (t=0; t<N && !Disabled[i]; ++t) {
			if ( i==t ) continue;
			for (k=0, j=1; j<=L[t]; ++j) {
				while (C[i][k+1]!=C[t][j] && k) k=pi[k];
				if (C[i][k+1]==C[t][j]) ++k;
				if (k==L[i]) {
					Disabled[i] = true;
					break;
				}
			}
			tmp[t] = k;
		} 
		if ( !Disabled[i] )
			for (j=0; j<N; ++j)
				G[j][i] = tmp[j];
	}

	// dinamica O(N^2*2^N) in
	/*
	   A[i][mask] = lungimea minima a secventei care se termina
	   in C[i] si are folosite elementele din repr binara a mastii
	*/
	memset(A, 0x3f, sizeof(A));
	M = (1<<N) - 1;
	for (i=0; i<N; ++i) {
		if ( Disabled[i] ) {
			M -= 1<<i;
			continue;
		}
		A[i][1<<i] = L[i];
		Q.push(1<<i); Used[1<<i] = true;
	}
	while ( !Q.empty() ) {
		int x = Q.front(); Q.pop(); Used[x] = false;
		for (i=0; i<N; ++i) {
			if ( (x&(1<<i))==0 ) continue;
			for (int j=0; j<N; ++j) {
				if ( Disabled[j] || (x&(1<<j)) ) continue;
				int y = x + (1<<j);
				if ( !Used[y] ) { Q.push(y); Used[y] = true; }
				if ( A[j][y] > A[i][x] + L[j] - G[i][j] )
					A[j][y] = A[i][x] + L[j] - G[i][j], Last[j][y] = i;
			}
		}
	}

	int m = 0;
	for (i=1; i<N; ++i)
		if ( A[i][M] < A[m][M] ) 
			m = i;

	back_print(m, M);
	out << "\n";
	return 0;
}