Cod sursa(job #3132284)

Utilizator TeodoraMaria123Serban Teodora Maria TeodoraMaria123 Data 22 mai 2023 01:46:41
Problema ADN Scor 100
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 5.11 kb
#include <bits/stdc++.h>

using namespace std;

#define pb push_back
#define MAX_N 18
#define MAX_STATE 263000
const int inf = INT_MAX;

int n, minCost;
int c[MAX_N + 1][MAX_N + 1], poz[MAX_N + 1][MAX_N + 1];
int dp[MAX_STATE][19];
short ult[MAX_STATE][19];
vector <string> secvente;
vector <int> pi, sol, indexes;

int kmp(int x, int y)/// suprapune b + a
{
    pi.clear();
    int aSize = secvente[x].size();
    int bSize = secvente[y].size();
    string a = secvente[x] + '#' + secvente[y];
    pi.resize(a.size() + 1);

    int j;
    bool ok = 1;
    for(int i = 1; i < a.size() &&  ok; i ++)
    {
        j = pi[i - 1];
        while(j  &&  a[j] != a[i])
            j = pi[j - 1];
        if(a[j] == a[i])
            j ++;
        pi[i] = j;
        if(pi[i] == aSize)
            ok = 0;
    }

    if(ok)
    {
        poz[y][x] = bSize - pi[a.size() - 1];/// poz de la care incepe al doilea string cand le suprapui
        return aSize - pi[a.size() - 1];
    }

    poz[y][x] = -1;
    return 0;
}

void display(int x, int limit)
{
//    if(limit == -1)
//        limit = secvente[x]
    for(int i = 0; i < limit; i ++)
        cout << secvente[x][i];
//    cout << limit << "\n";
//    cout << secvente[y];
}

void rebuildPath(int last)
{
    int mask = (1 << (indexes.size())) - 1;
//    cout << "Cale\n";
    while(mask)
    {
        sol.pb(last);
        int copyLast = last;
//        cout << last << " ";
//        cout << mask << "\n";
        last = ult[mask][last];
        mask -= (1 << copyLast);
    }

//    cout << "\n";
    for(int i = sol.size() - 1; i > 0; i --)
    {
//        cout << "\n" << indexes[sol[i]] << " " << indexes[sol[i - 1]] << "\n";
        display(indexes[sol[i]], poz[indexes[sol[i]]][indexes[sol[i - 1]]]);
    }
    display(indexes[sol[0]], secvente[indexes[sol[0]]].size());
}

int main()
{
    ios_base :: sync_with_stdio(0);
    cin.tie(0);

    freopen("adn.in", "r", stdin);
    freopen("adn.out", "w", stdout);

    cin >> n;

    minCost = INT_MAX;
    secvente.resize(n + 1);
    for(int i = 0; i < n; i ++)
    {
        cin >> secvente[i];
    }

    bool isLastIndependent = 1;
    for(int i = 0; i < n - 1; i ++)
    {
        bool isIndependent = 1;
        for(int j = i + 1; j < n; j ++)
        {
            c[i][j] = kmp(j, i);
            c[j][i] = kmp(i, j);
            if(c[j][i]  == 0)
                isIndependent = 0;
            if(j == n - 1  &&  c[i][j] == 0)
                isLastIndependent = 0;
//            cout << i << " " << j << " " << c[i][j] << " " << poz[i][j] << " " << c[j][i] << " " << poz[j][i] << "\n";
        }
        if(isIndependent)
        {
            indexes.pb(i);
        }
//        else cout << "ddds" << i;
    }
//    cout << "\n" << indexes.size() << "\n";
    if(isLastIndependent)
    {
        indexes.pb(n - 1);
    }

//    cout << indexes.size();
    int noMasks = (1 << (indexes.size())) - 1;

    for(int mask = 0; mask <= noMasks; mask ++)
        for(int i = 0; i < indexes.size(); i ++)
            dp[mask][i] = inf;

    for(int i = 0; i < indexes.size(); i ++)
        dp[1 << i][i] = secvente[indexes[i]].size();


    for(int mask = 1; mask < noMasks; mask ++)
    {
        for(int i = 0; i < indexes.size(); i ++)
        {
            if(mask & (1 << i))
                for(int poz = 0; poz < indexes.size(); poz ++)
                    if((mask & (1 << poz))  &&  dp[mask - (1 << poz)][i] != inf)
                    {
                        if(dp[mask][poz] > dp[mask - (1 << poz)][i] + c[indexes[i]][indexes[poz]])
                        {
                            dp[mask][poz] = dp[mask - (1 << poz)][i] + c[indexes[i]][indexes[poz]];
                            ult[mask][poz] = i;
                        }
                    }

        }
    }


//    for(int mask = 1; mask <= noMasks; mask ++) /// mask = 0 sau 1  ?? 1
//    {
//        cout << mask << ": ";
//        for(int i = 0; i < n; i ++)
//        {
//            cout << dp[mask][i] << " ";
//        }
//        cout << "\n";
//    }

    int mask = noMasks, lastNode = -1;
//        cout << "no a " << noMasks << "\n";
    for(int i = 0; i < indexes.size(); i ++)
    {
        if(mask & (1 << i))
            for(int poz = 0; poz < indexes.size(); poz ++)
                if((mask & (1 << poz))  &&  dp[mask - (1 << poz)][i] != inf)
                {
                    if(dp[mask][poz] > dp[mask - (1 << poz)][i] + c[indexes[i]][indexes[poz]])
                    {

                        dp[mask][poz] = dp[mask - (1 << poz)][i] + c[indexes[i]][indexes[poz]];
//                        cout << "am intrat" << mask << "  " << poz << "  " << dp[mask][poz] << "\n";
                        ult[mask][poz] = i;
                        if(dp[mask][poz] < minCost)
                        {
                            minCost = dp[mask][poz];
                            lastNode = poz;
                        }
                    }
                }
    }

    rebuildPath(lastNode);
//    cout << minCost;
    return 0;
}