Cod sursa(job #1743715)

Utilizator PTAdrian64Pop-Tifrea Adrian PTAdrian64 Data 18 august 2016 16:41:40
Problema ADN Scor 70
Compilator cpp Status done
Runda Arhiva de probleme Marime 3.06 kb
#include <cstring>
#include <cstdio>
#include <string>
#include <fstream>
#define maxlen 30001
#define inf 0x3f3f3f3f

using namespace std;

int N,used;
int length[19];
char s[19][maxlen];
int prefix[maxlen];
int pref[19][19];
int best[1 << 18][19]; //best[i][j] = costul unui lant hamiltonian de configuratie i si care il contine pe j
int pred[1 << 18][19]; //pred[i][j] = nodul predecesor nodului j din cel mai scurt lant hamiltonian cu configuratia i

void make_prefix(int l2){

  //aceasta functie calculeaza vectorul prefix pentru KMP
  //prefix[i] = cel mai lung prefix al lui s[l2] care este sufix al lui s[l2]i

  int k = 0,i;

  prefix[0] = 1;
  
  for(i = 2; s[l2][i]; ++i){

    while(k != 0 && s[l2][k + 1] != s[l2][i])k = prefix[k];
    if(s[l2][i] == s[l2][i])k++;
    prefix[i] = k;
    
  }
  
}

int kmp(int l1,int l2){

  //

  int k = 0,i,j;

  k = 0;

  for(i = 1; s[l1][i]; ++i){

    while(k != 0 && s[l1][i] != s[l2][k + 1])
      k = prefix[k];

    if(s[l1][i] == s[l2][k + 1])k++;
    if(s[l2][k + 1] == '\0')return k;
    
  }

  return k;
  
}

int main(){

  ifstream fin("adn.in");
  ofstream fout("adn.out");

  //citire:
  
  (fin >> N).ignore();
  int i,j,ret,k;
  
  for(i = 0;i < N;++i){

    fin.getline(s[i] + 1,maxlen);
    length[i] = strlen(s[i] + 1);
    
  }

  //elimiarea sirurilor:
  
  for(i = 0;i < N;++i){

    make_prefix(i);
    
    for(j = 0;j < N;++j)
      if(i != j){

	ret = kmp(j,i);
	if(ret == length[i]){

	  used |= 1 << i;  // used = reprezentarea binara a cuvintelor folosite ( bitul i este 1 daca cuvantul s[i] se
	                   // gaseste in alt cuvant)
	  break;
	  
	}
	else pref[j][i] = length[i] - ret;         //cel mai lung sufix al cuvantului s[i]
	                                           //care este prefix al cuvantului s[j]
	
      }
    
  }

  for(i = 1;i < (1 << N);++i)
    for(j = 0;j < N;++j)best[i][j] = inf;
  
  for(i = 0;i < N;++i)
    best[1 << i][i] = length[i];

  for(i = 1;i < (1 << N);++i)
    if((i & used) == 0 && (i & (i - 1))){  //daca cuvantul i nu se afla in alt cuvant si daca i nu este putere a lui 2

      for(j = 0;j < N;++j)
	if(i & (1 << j))  // daca bitul j din reprezentarea pe biti a lui i este 1
	  {
	    for(k = 0;k < N;++k)
	      if(j != k && (i & (1 << k)) && best[i][j] > best[i ^ (1 << j)][k] + pref[k][j]){

		best[i][j] = best[i ^ (1 << j)][k] + pref[k][j];
		pred[i][j] = k;
		
	      }
	  }
      
    }

  int mask = ((1 << N) - 1) ^ used;  // mask = toate cuvintele  care nu sunt in used

  //se identifica un k astfel incat best[mask][k] sa fie minim (cel mai scurt lant hamiltonian)
 
  for(k = -1,j = 0;j < N;++j){

    if((used & (1 << j)) == 0) // daca cuvantul s[j] apare in alt cuvant
      if(k == -1 || best[mask][j] < best[mask][k])
	k = j;
    
  }

  string R;
  for(i = mask; i; k = j){

    j = pred[i][k];
    i ^= 1 << k;  // se elimina nodul k din lant
    if(i) R.insert(R.begin(), s[k] + length[k] + 1 - pref[j][k], s[k] + length[k] + 1);
    else  R.insert(R.begin(), s[k] + 1, s[k] + length[k] + 1);
    
  }

  fout << R << "\n";

  fin.close();
  fout.close();
  
  return 0;
  
}