Cod sursa(job #2133821)

Utilizator sabinandreiBocan Sabin Andrei sabinandrei Data 17 februarie 2018 12:49:12
Problema ADN Scor 100
Compilator cpp Status done
Runda Arhiva de probleme Marime 3.33 kb
#include <cstring>
#include <cstdio>
#include <string>
#include <fstream>
#define maxlen 30010
#define inf 1000000000
 
using namespace std;
 
int N,used,mask;
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 l1){
 
  //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[l1][i]; ++i){
 
    while(k != 0 && s[l1][k + 1] != s[l1][i])k = prefix[k];
    if(s[l1][k + 1] == s[l1][i])k++;
    prefix[i] = k;
     
  }
   
}
 
int kmp(int l1,int l2){
 
  //
 
  int k = 0,i;
 
  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;
         
          }
      }
       
    }
 
  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;
   
}