Cod sursa(job #2546740)

Utilizator memecoinMeme Coin memecoin Data 14 februarie 2020 14:03:15
Problema ADN Scor 0
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 4.72 kb
#include <fstream>
#include <iomanip>
#include <string>
#include <stdio.h>
#include <vector>
#include <algorithm>
#include <math.h>
#include <set>
#include <map>
#include <string.h>
#include <queue>
#include <stack>

#define INF 0x3f3f3f3f

using namespace std;

#ifdef DEBUG
string name = "data";
#else
string name = "data";
#endif

ifstream fin(name + ".in");
ofstream fout(name + ".out");

#define MAXN 18
#define MAXL 30005
int ns;
int n;
string s[MAXN];

int pi[MAXN][MAXL];
int toRemove[MAXN];
int d[MAXN][MAXN];

vector<string> sf;

void buildPi(string &s, int *pi) {
    int i = 1;
    int j = 0;
    
    while (i < s.size()) {
        if (s[i] == s[j]) {
            j++;
            pi[i] = j;
            i++;
        } else {
            if (j == 0) {
                i++;
            } else {
                j = pi[j - 1];
            }
        }
    }
}

bool contains(string &t, int i) {
    
    string sb = s[i];
    auto p = pi[i];
    
    if (t.size() < sb.size()) {
        return false;
    }
    
    i = 0;
    int j = 0;
    
    while (i < t.size()) {
        if (t[i] == sb[j]) {
            i++;
            j++;
            if (j >= sb.size()) {
                return true;
            }
        } else {
            if (j == 0) {
                i++;
            } else {
                j = p[j - 1];
            }
        }
    }
    
    return false;
}

int computeOverlap(string &t, int i) {
    string sb = sf[i];
    auto p = pi[i];
    
    i = 1;
    int j = 0;
    
    while (i < t.size()) {
        if (t[i] == sb[j]) {
            i++;
            j++;
        } else {
            if (j == 0) {
                i++;
            } else {
                j = p[j - 1];
            }
        }
    }
    
    return (int)(sb.size() - j);
}

void buildGraph() {
    fin >> ns;
    for (int i = 0; i < ns; ++i) {
        fin >> s[i];
    }
    
    for (int i = 0; i < ns; ++i) {
        buildPi(s[i], pi[i]);
    }
    
    for (int i = 0; i < ns; ++i) {
        for (int j = 0; j < ns; ++j) {
            if (!toRemove[i] && !toRemove[j] && i != j && contains(s[i], j)) {
                toRemove[j] = true;
            }
        }
    }
    
    n = ns;
    
    for (int i = 0; i < ns; ++i) {
        if (!toRemove[i]) {
            sf.push_back(s[i]);
        } else {
            n--;
        }
    }
    
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < n; ++j) {
            if (i != j) {
                d[i][j] = computeOverlap(sf[i], j);
            } else {
                d[i][j] = INF;
            }
        }
    }
}

void gen(int k, int bit, int nrOne, vector<int> &result) {
    if (bit > (n - nrOne)) {
        return;
    }
    
    if (nrOne == 0) {
        result.push_back(k);
        return;
    }
    
    gen(k | (1 << bit), bit + 1, nrOne - 1, result);
    gen(k, bit + 1, nrOne, result);
}

vector<int> genNr(int nrOne) {
    vector<int> result;
    
    if (nrOne == 0) {
        result.push_back(0);
        return result;
    }
    
    gen(1, 1, nrOne - 1, result);
    
    return result;
}

int best[1 << MAXN][MAXN];
int parent[1 << MAXN][MAXN];

void hamiltonianPath() {
    memset(best, 0x3f, sizeof(best));
    
    for (int i = 0; i < n; ++i) {
        best[1 << i][i] = (int)sf[i].size();
    }
    
    for (int i = 2; i <= n; ++i) {
        auto v = genNr(i);
        
        for (int x: v) {
            for (int bit = 0; bit < n; ++bit) {
                for (int j = 0; j < n; ++j) {
                    if (!(x & (1 << j))) {
                        continue;
                    }
                    
                    if (d[j][bit] != INF) {
                        if (best[x & (~(1 << bit))][j] + d[j][bit] < best[x][bit]) {
                            best[x][bit] = best[x & (~(1 << bit))][j] + d[j][bit];
                            parent[x][bit] = j;
                        }
                    }
                }
            }
        }
    }
    
    int bestest = INF;
    int lastNode = 0;
    
    for (int i = 0; i < n; ++i) {
        if (best[(1 << n) - 1][i] < bestest) {
            bestest = best[(1 << n) - 1][i];
            lastNode = i;
        }
    }

    int state = (1 << n) - 1;
    
    vector<int> sol;

    while (state > 0) {
        sol.push_back(lastNode);
        
        int nextNode = parent[state][lastNode];
        
        state = state & (~(1 << lastNode));
        
        lastNode = nextNode;
    }
    
    reverse(sol.begin(), sol.end());
    
    fout << sf[sol[0]];
    for (int i = 1; i < sol.size(); ++i) {
        int k = sol[i];
        int l = sol[i - 1];
        
        for (int j = (int)(sf[k].size() - d[l][k]); j < sf[k].size(); ++j) {
            fout << sf[k][j];
        }
    }
}

int main() {
    
    buildGraph();
    hamiltonianPath();
    
    return 0;
}