Cod sursa(job #2791204)

Utilizator cristi_macoveiMacovei Cristian cristi_macovei Data 30 octombrie 2021 10:58:55
Problema ADN Scor 100
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 3.18 kb
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <algorithm>

#define inout(f) std::ifstream in((f) + (std::string) ".in");std::ofstream out((f) + (std::string) ".out")
#define d(x) std::cout << x << std::endl
#define dm(msg, x) std::cout << msg << x << std::endl

const int NMAX = 18;

int n;
std::string a[1 + NMAX];

bool skipped[1 + NMAX];

int weights[1 + NMAX][1 + NMAX];

std::vector<std::pair<int, int>> reverseGraph[1 + NMAX];
int dp[(1 << NMAX)][1 + NMAX];
std::pair<int, int> prev[(1 << NMAX)][1 + NMAX];

void removeSkipped() {
  int write = 0;
  for (int read = 0; read < n; ++read) {
    if (!skipped[read]) {
      a[write] = a[read];
      ++write;
    }
  }

  n = write;
}

int cntMatchingCharacters(const std::string& a, const std::string& b) {
  std::string concat = "." + b + "." + a;

  std::vector<int> pi(concat.size(), 0);
  
  int k = 0;
  pi[1] = 0;

  for (int i = 2; i < concat.size(); ++i) {
    while (k > 0 && concat[k + 1] != concat[i])
      k = pi[k];

    if (concat[k + 1] == concat[i])
      ++k;

    pi[i] = k;
  }

  return pi.back();
}

void print(const std::pair<int, int>& current, std::ostream& os) {
  if (current.first == 0)
    return;

  print(prev[current.first][current.second], os);

  int edgeWeight = weights[prev[current.first][current.second].second][current.second];
  if (prev[current.first][current.second].first == 0)
    edgeWeight = 0;

  os << a[current.second].substr(edgeWeight);
}

int main() {
  inout("adn");

  in >> n;

  for (int i = 0; i < n; ++i)
    in >> a[i];

  std::sort(a, a + n, [] (const std::string& i, const std::string& j) -> bool {
    return i.size() < j.size();
  });

  for (int i = 0; i < n; ++i) {
    for (int j = i + 1; j < n; ++j) {
      if (a[j].find(a[i]) != std::string::npos) {
        skipped[i] = true;
        break;
      }
    }
  }

  removeSkipped();
  
  for (int i = 0; i < n; ++i) {
    for (int j = 0; j < n; ++j) {
      if (i != j) {
        int edgeWeight = cntMatchingCharacters(a[i], a[j]);

        weights[i][j] = edgeWeight;

        reverseGraph[j].emplace_back(i, edgeWeight);
      }
    }
  }
  
  // hamilton   
  for (int mask = 0; mask < (1 << n); ++mask) {
    for (int last = 0; last < n; ++last) {
      dp[mask][last] = -1;
    }
  }

  for (int first = 0; first < n; ++first) 
    dp[(1 << first)][first] = 0;

  for (int mask = 0; mask < (1 << n); ++mask) {
    for (int last = 0; last < n; ++last) {
      if (!(mask & (1 << last)))
        continue;

      int newMask = mask ^ (1 << last);
      for (const auto& edge: reverseGraph[last]) {
        if (mask & (1 << edge.first)) {
          if (dp[newMask][edge.first] + edge.second > dp[mask][last]) {
            dp[mask][last] = dp[newMask][edge.first] + edge.second;
            prev[mask][last] = {newMask, edge.first};
          }
        }
      }
    }
  }
  
  int len = -1;
  std::pair<int, int> best;
  for (int i = 0; i < n; ++i)  {
    if (dp[(1 << n) - 1][i] > len) {
      len = dp[(1 << n) - 1][i];
      best = {(1 << n) - 1, i};
    }
  }

  print(best, out);

  return 0;
}