Cod sursa(job #2967297)

Utilizator maria-marianita.cucos@s.unibuc.roCucos Marianita [email protected] Data 19 ianuarie 2023 11:45:16
Problema ADN Scor 100
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 5.98 kb
#include<bits/stdc++.h>

#define lmax 30003 //lungime maxima sir caractere
#define nmax 19 //numar maxim siruri
using namespace std;

ifstream in("adn.in");
ofstream out("adn.out");
/*
Idee: se foloseste algoritm Knuth-Morris-Pratt (kmp); se determina sirurile care sunt in alte siruri si se elimina
*/

int n; //numar siruri

char sir[nmax][lmax]; //secventele date
int lungime[nmax]; //lungimile secventelor date

int potrivit[nmax][nmax]; //indici secvente comune
int cost[(1<<nmax)][nmax]; //cost[i][j] cel mai lung sufix din i care este prefix in j
int idxprev[(1<<nmax)][nmax]; //indice anterior
int ultim; //ultimul indice vizat
vector<int> secv[nmax];
vector<int> rez;
int poz[lmax];


void init() //datele de intrare
{
    in>>n;

    for(int i=1; i<=n; i++)
    {
        in>>sir[i];
        lungime[i] = strlen(sir[i]);
    }
}

void kmp_sterge() //sterg siruri incluse in altele
{
    bool desters[n+1];
    for(int i=1; i<=n ; i++)
        desters[i]=0;

    bool gasit;

    for(int i=1; i<=n; i++)
    {
        if (desters[i]==0)
        {
            for (int j=1; j<=n; j++)
            {
                if (i!=j && desters[j]==0)
                {
                    int i1=0, i2=1;
                    for (int k=0; k<lungime[i]; k++)
                    {
                        poz[k]=0;
                    }
                    while(i2<lungime[i])
                    {
                        if (sir[i][i1]==sir[i][i2])
                        {
                            poz[i2]=i1+1;
                            i1++;
                            i2++;
                        }
                        else if (i1)
                            i1=poz[i1-1];
                        else i2++;
                    }
                    gasit=0;
                    i1=0;
                    for (i2=0; i2<lungime[j]; i2++)
                    {
                        if (sir[i][i1] == sir[j][i2])
                            i1++;
                        else if (i1 != 0)
                        {
                            i1=poz[i1-1];
                            i2--;
                        }
                        if (i1==lungime[i])
                        {
                            gasit=1;
                            break;
                        }
                    }
                    if(gasit)
                    {
                        desters[i]=1;
                    }
                }
            }
        }
    }

    int l=0;
    for(int i=1; i<=n; i++)
    {
        if (desters[i] == 0)
        {
            l++;
            strcpy(sir[l], sir[i]);
        }
    }

    n=l;

    //recalculare lungimi dupa stergere
    for(int i=1; i<=n; i++)
        lungime[i]=strlen(sir[i]);
}

void kmp_cost() //calculez costurile (cost[i][j]=lungimea maxima sufix din sir[i] care e prefix in sir[j])
{
    for (int i=1; i<=n; i++)
    {
        for (int j=1; j<=n; j++)
        {
            if (i!=j)
            {
                int i1=0;
                int i2=1;
                for(int k=0; k<lungime[j]; k++)
                    poz[k]=0;
                while(i2<lungime[j])
                {
                    if(sir[j][i1]==sir[j][i2])
                    {
                        poz[i2]=i1+1;
                        i1++;
                        i2++;
                    }
                    else if (i1)
                        i1=poz[i1-1];
                    else i2++;
                }
                i1=0;
                for(i2=0; i2<lungime[i]; i2++)
                {
                    if (sir[j][i1]==sir[i][i2])
                        i1++;
                    else if(i1!=0)
                    {
                        i1=poz[i1-1];
                        i2--;
                    }
                }
                secv[i].push_back(j);
                potrivit[i][j]=i1; //index de la care incepe sufixul
            }
        }
    }

    //initializare cost
    for(int i=0; i<(1<<n); i++)
    {
        for(int j=1; j<=n; j++)
        {
            cost[i][j]=-10000000;
        }
    }

    for(int i=1; i<=n; i++)
    {
        cost[(1<<(i-1))][i]=0;
    }

    int cost_max=0;
    //calcul costuri (cel mai mare lant hamiltonian)
    for (int i=0; i<(1<<n); i++)
    {
        for (int j=1; j<=n; j++)
        {
            if(i&(1<<(j-1)))
            {
                for(int x:secv[j])
                {
                    if (!(i&(1<<(x-1))))
                    {
                        int k=i+(1<<(x-1));
                        if(cost[k][x]<cost[i][j]+potrivit[j][x])
                        {
                            cost[k][x]=max(cost[k][x], cost[i][j] + potrivit[j][x]);
                            idxprev[k][x]=j;
                        }
                        if (cost[k][x]>=cost_max)
                        {
                            cost_max=cost[k][x];
                            ultim=x;
                        }
                    }
                }
            }
        }
    }
}

int main()
{
    init();
    kmp_sterge();
    kmp_cost();

    if (n==1)
        rez.push_back(n);
    else
    {
        int nr=0;
        rez.push_back(ultim);
        int m=(1<<n)-1;
        if (n>=2)
        {
            while(nr != 1)
            {
                int nod=idxprev[m][ultim];
                rez.push_back(nod);
                m = m-(1<<(ultim-1));
                ultim = nod;
                nr = 0;
                for(int i=1; i<=n; i++)
                {
                    if(m & (1<<(i-1)))
                        nr++;
                }
            }
        }
    }

    // afisez rezultatul
    for (int i=rez.size()-1; i>=1; i--)
    {
        int lg = lungime[rez[i]];
        for (int j=0; j<lg-potrivit[rez[i]][rez[i-1]]; j++)
            out<<sir[rez[i]][j];
    }
    out<<sir[rez[0]];

    return 0;
}