Cod sursa(job #1571553)

Utilizator claudiuarseneClaudiu Arsene claudiuarsene Data 18 ianuarie 2016 10:10:05
Problema ADN Scor 100
Compilator cpp Status done
Runda Arhiva de probleme Marime 2.59 kb
#include <fstream>
#include <cstring>
#include <algorithm>

const int MAX_N = 18;
const int MAX_LEN = 30000;
const int INF = 0x3f3f3f3f;

using namespace std;

char S[MAX_N][MAX_LEN + 1];
int stLength[MAX_N];
int C[MAX_N][MAX_N];
int D[1 << MAX_N][MAX_N];
int from[1 << MAX_N][MAX_N];

int FindCost(int A, int B) {
  static char tmp[2 * MAX_LEN + 2];
  static int Z[2 * MAX_LEN + 1];
  const int m_size = stLength[A] + stLength[B] + 1;
  int l, r;

  memmove(tmp, S[B], stLength[B]);
  tmp[stLength[B]] = '$';
  memmove(tmp + stLength[B] + 1, S[A], stLength[A]);
  tmp[m_size] = '\0';

  l = r = 0;
  for (int i = 1; i < m_size; i++) {
    if (i <= r)
      Z[i] = min(Z[i - l], r - i + 1);
    else
      Z[i] = 0;

    while (tmp[Z[i]] == tmp[i + Z[i]])
      Z[i]++;
    if (i + Z[i] - 1 > r) {
      r = i + Z[i] - 1;
      l = i;
    }
  }

  int maxZ = 0;
  for (int i = 1 + stLength[B]; i < m_size; i++)
    if ((i + Z[i] == m_size || Z[i] == stLength[B]) && (maxZ < Z[i]))
      maxZ = Z[i];

  return stLength[B] - maxZ;
}

void Reconstituire(int mask, int node, ofstream &out) {
  if (mask & (mask - 1)) {
    const int fromNode = from[mask][node];
    Reconstituire(mask ^ (1 << node), fromNode, out);
    out << S[node] + (stLength[node] - C[fromNode][node]);
  } else {
    out << S[node];
  }
}

int main() {
  ifstream in("adn.in");
  ofstream out("adn.out");
  in.tie(0);
  ios_base::sync_with_stdio(0);
  int N;
  int disconsiderMask;

  in >> N;
  for (int i = 0; i < N; i++) {
    in >> S[i];
    D[1 << i][i] = stLength[i] = strlen(S[i]);
  }

  disconsiderMask = 0;
  for (int i = 0; i < N; i++)
    for (int j = 0; j < N; j++)
      if (i != j) {
        C[i][j] = FindCost(i, j);
        disconsiderMask |= (1 << j) & -(C[i][j] == 0);
      }

  for (int i = 3; i < (1 << N); i++) {
    if (i & (i - 1))
      memset(D[i], INF, 4 * N);
  }

  for (int mask = 1; mask < (1 << N); mask++) {
    for (int fn1 = 0; fn1 < N; fn1++) {
      if ((mask >> fn1) & 1) {
        for (int fn2 = 0; fn2 < N; fn2++) {
          const int newMask = mask | (1 << fn2);
          const int cost = D[mask][fn1] + C[fn1][fn2];
          if ((mask != newMask) && (D[newMask][fn2] > cost)) {
            D[newMask][fn2] = cost;
            from[newMask][fn2] = fn1;
          }
        }
      }
    }
  }

  int node = 0;
  int mask = ((1 << N) - 1) ^ disconsiderMask;
  for (int i = 1; i < N; i++) {
    if (D[mask][i] < D[mask][node]) {
      node = i;
    }
  }

  Reconstituire(mask, node, out);

  out.close();
  return 0;
}