Cod sursa(job #1067997)

Utilizator vlad_DVlad Dumitriu vlad_D Data 27 decembrie 2013 19:46:19
Problema ADN Scor 50
Compilator cpp Status done
Runda Arhiva de probleme Marime 2.15 kb
#include <cstdio>
#include <signal.h>
#include <iostream>
#include <string.h>

using namespace std;

int N;
char adn[19][30007];
int F[19][30007];
int M[19];

void build_failure() {
  for (int k = 0; k < N; ++k) {
    char* pat = adn[k];
    F[k][0] = F[k][1] = 0;
    for (int i = 2; i <= M[k]; ++i) {
      F[k][i] = 0;
      int j = F[k][i-1];
      while (j) {
        if (pat[j] == pat[i-1]) {
          F[k][i] = j + 1; break;
        }
        j = F[k][j];
      }
    }
  }
}
int hash_kmp[20][20];
int kmp(int k1, int k2) {
  if (hash_kmp[k1][k2]) return hash_kmp[k1][k2] - 1;
  // k1 ... k2
  int& best = hash_kmp[k1][k2];
  int i = 0, j = 0;
  char* text = adn[k1];
  char* pat = adn[k2];
  while (1) {
    if (i == M[k1]) break; 
    if (text[i] == pat[j]) {
      ++i; ++j;
      if (i == M[k1] || j == M[k2]) { best = j + 1; return best - 1; }
    } else {
      if (j > 0) j = F[k2][j];
      else ++i;
    }
  }
  best = 1;
  return 0;
}

int dp[1<<18][18];
int go(int mask, int p) {
  if (mask + 1 == (1<<N)) return 0;
  if (dp[mask][p]) return dp[mask][p] - 1;
  int& ret = dp[mask][p];
  ret = 30000 * N + 1;
  for (int i = 0; i < N; ++i) if (!(mask&(1<<i))) {
    int now = M[i] - kmp(p, i) + go(mask|(1<<i), (M[i]-kmp(p,i))?i:p);
    if (now < ret) ret = now;
  }
  ret += 1;
  return ret - 1;
}

int main() {
  freopen("adn.in", "r", stdin);
  freopen("adn.out", "w", stdout);
  scanf("%d", &N);
  for (int i = 0; i < N; ++i) {
    scanf("%s", &adn[i]);
    M[i] = strlen(adn[i]);
  }
  build_failure();
  int best = 30000 * N + 1;
  int last_i = 0;
  for (int i = 0; i < N; ++i) {
    int now = go((1<<i), i) + M[i];
    if (now < best) best = now, last_i = i;
  }
  printf("%s", adn[last_i]);
  int mask = (1<<last_i); best -= M[last_i];

  while (mask + 1 != (1<<N)) {
    for (int i = 0; i < N; ++i) if (!(mask & (1<<i))) {
      int now = go(mask | (1<<i), (M[i]-kmp(last_i,i))?i:last_i) + M[i] - kmp(last_i, i);
      if (now == best) {
        best -= M[i] - kmp(last_i, i);
        printf("%s", adn[i] + kmp(last_i, i));
        if (kmp(last_i, i) != M[i]) last_i = i;
        mask |= (1<<i);
      }
    }
  }
  printf("\n");
  fclose(stdin);
  fclose(stdout);
  return 0;
}