Cod sursa(job #2634470)

Utilizator stefan.popescuPopescu Stefan stefan.popescu Data 11 iulie 2020 00:30:02
Problema ADN Scor 40
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 4.14 kb
#include <iostream>
#include <fstream>
#include <vector>
#include <string.h>
using namespace std;
ifstream in ("adn.in");
ofstream out("adn.out");
vector <pair <string, vector <short> > > a;
vector <bool> usable;
vector < vector <short> > lpsTable;
int n, lenfin;
void generateLPS(pair <string, vector <short> > &);
vector <string> b;
bool isInside(pair <string, vector <short> > &, pair <string, vector <short> > &);
int dualLPS(string &, string &);
int dp[18][(1<<18)]; ///suma maxima cu a unui lant care se termina cu i si contine bitii lui j ca submultime
short dp2[18][(1<<18)]; ///nodul din care a venit configuratia actuala

void show(int nod, int nr, int mask)
{
    int nodant=dp2[nod][mask], maskant=mask-(1<<nod), folosite=b[nodant].size()-(dp[nod][mask]-dp[nodant][maskant]);

    if(nodant!=nod)
        show(nodant, folosite, maskant);

    for(int i=0; i<nr; i++)
        out<<b[nod][i];
}
int main()
{
    in>>n;
    usable.resize(n, true);
    for(int i=1; i<=n; i++)
    {
        a.resize(a.size()+1);
        in>>a.back().first;
        generateLPS(a.back());
    }
    for(int i=0; i<(int)a.size(); i++)
        for(int j=0; j<(int)a.size(); j++)
            if(j!=i)
                if(isInside(a[i], a[j]))
                {usable[i]=false; break;}
    for(int i=0; i<(int)a.size(); i++)
        if(usable[i])
            b.push_back(a[i].first), lenfin+=b.back().size();
    a.clear(); a.shrink_to_fit();
    n=b.size();
    lpsTable.resize(b.size(), vector <short>(b.size(), 0));

    for(int i=0; i<n; i++)
        for(int j=0; j<n; j++)
            if(i!=j)
                lpsTable[i][j]=dualLPS(b[i], b[j]); ///cel mai lung sufix al primului care e prefix in al doilea

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

    for(int mask=1; mask<=(1<<n)-1; mask++)
    {
        for(int elem=0; elem<n; elem++)
        {
            if((1<<elem) & mask) ///adica elementul exista in submultimea actuala;
            {
                int mask2=mask-(1<<elem); ///masca submultimii fara elementul actual
                int origine=elem, maxi=-1;
                for(int i=0; i<n; i++) ///iterez prin toate posibilitatile de venire
                    if((1<<i) & mask2)
                        if(maxi<dp[i][mask2]+lpsTable[i][elem])
                            maxi=dp[i][mask2]+lpsTable[i][elem], origine=i;

                if(maxi==-1) maxi=0;

                dp[elem][mask]=maxi; dp2[elem][mask]=origine;
            }
        }
    }
    int maxi=-1, origine=-1;
    for(int i=0; i<n; i++)
        if(maxi<dp[i][(1<<n)-1])
            maxi=dp[i][(1<<n)-1], origine=i;

    show(origine, b[origine].size(), (1<<n)-1);

    return 0;
}
///*******************************************************************************************************************************************************///
void generateLPS(pair <string, vector <short> > & per)
{
    string & s=per.first;
    vector <short> & lps=per.second;

    lps.resize(s.size(), 0);
    int len=0;

    for(int i=1; i<(int)s.size(); i++)
    {
        while(s[i]!=s[len]&&len!=0)
            len=lps[len-1];
        if(s[i]==s[len])
            len++;
        lps[i]=len;
    }
}
bool isInside(pair <string, vector <short> > & per1, pair <string, vector <short> > & per2)
{
    string & s1=per1.first; string & s2=per2.first; vector <short> & lps1=per1.second;
    if(s1.size()>s2.size()) return false;
    int len=0;
    for(int i=0; i<(int)s2.size(); i++)
    {
        while(s2[i]!=s1[len]&&len>0)
            len=lps1[len-1];

        if(s2[i]==s1[len])
            len++;

        if(len==(int)s1.size())
            return true;
    }
    return false;
}
int dualLPS(string & s2, string & s1) ///longest suffix of s1 that is a prefix of s2
{
    vector <short> lps(s2.size(), 0); ///cel mai lung prefix al lui s1 care se potriveste cu sufixul lui s2 pana in i
    int len=0;
    for(int i=1; i<(int)s2.size(); i++)
    {
        while(s2[i]!=s1[len] && len!=0 )
            len=lps[len-1];

        if(s2[i]==s1[len] && len<(int)s1.size())
            len++;
        lps[i]=len;
    }
    return len;
}