Cod sursa(job #2986728)

Utilizator MihaiZ777MihaiZ MihaiZ777 Data 28 februarie 2023 23:22:15
Problema ADN Scor 100
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 4.99 kb
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <cstring>
using namespace std;

ifstream fin("adn.in");
ofstream fout("adn.out");

const int INF = 0x3f3f3f3f;

struct Edge {
    int destination;
    int cost;
};

int n;
string str[20];
int lps[60005];
vector <Edge> graph[20];
string a, s;

int costs[20][20];
bool absorbed[20];
int nodesNewToInit[20];
int nodesInitToNew[20];

int dp[1 << 18][20];
int previous[1 << 18][20];

vector <int> answerIndices;

int LPS(int aIdx, int bIdx) {
    s = '$' + str[aIdx] + '$' + str[bIdx];
    a = str[aIdx];

    int lenS = s.length();

    for (int i = 2; i < lenS; i++) {
        int currLetter = s[i];
        int currIdx = lps[i - 1];

        while (currIdx && currLetter != s[currIdx + 1]) {
            currIdx = lps[currIdx];
        }

        if (currLetter == s[currIdx + 1]) {
            currIdx++;
        }

        lps[i] = currIdx;
    }
    return lenS;
}

void BuildCostsMatrix() {
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++) {
            if (i == j) {
                continue;
            }
            /*
                   GGATATAAAAAC   = i
                TGGGGATATAAAA     = j
            */
            int lpsSize = LPS(i, j);
            int lenA = str[i].length();
            int startIdx = lenA + 2;
            
            int currLpsValue = -1; 
            for (int k = startIdx; k < lpsSize; k++) {
                currLpsValue = lps[k];
                // Check if it is included
                if (lps[k] == lenA) {
                    absorbed[i] = true;
                    break;
                } 
            }
            costs[j][i] = currLpsValue;
        }
    }
}

int BuildGraph() {
    memset(nodesInitToNew, INF, sizeof(nodesInitToNew));
    memset(nodesNewToInit, INF, sizeof(nodesNewToInit));

    int nodesCount = 0;
    for (int i = 1; i <= n; i++) {
        if (absorbed[i]) {
            continue;
        }
        nodesNewToInit[nodesCount] = i;
        nodesInitToNew[i] = nodesCount;
        nodesCount++;
    }

    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++) {
            if (i == j) {
                continue;
            }
            if (absorbed[i] || absorbed[j]) {
                continue;
            }

            if (costs[i][j]) {
                graph[nodesInitToNew[i]].push_back({nodesInitToNew[j], costs[i][j]});
            }
        }
    }
    return nodesCount;
}

void BuildDynamicConfiguration(int nodesCount) {
    memset(previous, INF, sizeof(previous));
    memset(dp, -1, sizeof(dp));

    for (int node = 0; node < nodesCount; node++) {
        int conf = 1 << node;
        dp[conf][node] = 0;
    }

    for (int conf = 1; conf < (1 << nodesCount); conf++) {
        for (int node = 0; node < nodesCount; node++) {
            if (dp[conf][node] == -1) {
                continue;
            }
            // if ((conf & (1 << node)) == 0) {
            //     continue;
            // }

            for (Edge edge : graph[node]) {
                if (conf & (1 << edge.destination)) {
                    continue;
                }

                int newConf = conf ^ (1 << edge.destination);
                if (dp[conf][node] + edge.cost > dp[newConf][edge.destination]) {
                    dp[newConf][edge.destination] = dp[conf][node] + edge.cost;
                    previous[newConf][edge.destination] = node;
                }
            }
        }
    } 
}

void BuildAnswerIndices(int nodesCount) {
    int ans = -1;
    int lastNode = -1;

    for (int node = 0; node < nodesCount; node++) {
        if (dp[(1 << nodesCount) - 1][node] == -1) {
            continue;
        }

        if (dp[(1 << nodesCount) - 1][node] > ans) {
            ans = dp[(1 << nodesCount) - 1][node] ;
            lastNode = node;
        }
    }

    int conf = (1 << nodesCount) - 1;
    int newNode = lastNode;
    cout << lastNode;
    while (conf) {
        lastNode = newNode;
        answerIndices.push_back(nodesNewToInit[lastNode]);

        newNode = previous[conf][lastNode];
        conf = conf ^ (1 << lastNode);
    }
}

void BuildAnswer() {
    int firstNode = answerIndices.back();
    fout << str[firstNode];
    answerIndices.pop_back();

    while (!answerIndices.empty()) {
        int secondNode = answerIndices.back();
        answerIndices.pop_back();
        int overlap = costs[firstNode][secondNode];
        int len = str[secondNode].length();
    
        for (int j = overlap; j < len; j++) {
            fout << str[secondNode][j];
        }

        firstNode = secondNode;
    }
}

int main() {
    fin >> n;
    for (int i = 1; i <= n; i++) {
        fin >> str[i]; 
    }

    BuildCostsMatrix();
    int nodesCount = BuildGraph();
    BuildDynamicConfiguration(nodesCount);
    BuildAnswerIndices(nodesCount);
    BuildAnswer();

    return 0;
}