Cod sursa(job #1009233)

Utilizator Andrei1998Andrei Constantinescu Andrei1998 Data 12 octombrie 2013 18:05:10
Problema ADN Scor 100
Compilator cpp Status done
Runda Arhiva de probleme Marime 3.42 kb
#include <fstream>
#include <cstring>
#include <bitset>

using namespace std;

char sir[18][30005];
int l[18];
int coresp[18][18];
int ram[18];
int pref[18][30005];
int din[262200][18];
int prec[262200][18];

#define INF 540200

int minim(int a,int b)
{
    if(a<b)
        return a;
    return b;
}

ifstream cin("adn.in");
ofstream cout("adn.out");

//Afiseaza sirul care, fara primele lui cate caractere
inline void afis(int care,int cate)
{
    int i;
    for(i=cate;i<l[care];i++)
        cout<<sir[care][i];
}

int main()
{
    int n=0,i,k,j,p,poz=0;
    bitset<18> elimin;

    cin>>n;
    for(i=0;i<n;i++)
    {
        cin.get();
        cin.get(sir[i],30005);
        l[i]=strlen(sir[i]);

        //Functia prefix (din KMP)
        k=0;
        pref[i][0]=0;
        for(j=1;j<l[i];j++)
        {
            while(k>0 && sir[i][j]!=sir[i][k])
                k=pref[i][k-1];
            if(sir[i][j]==sir[i][k])
                k++;
            pref[i][j]=k;
        }
    }

    //KMP pentru fiecare 2 siruri in parte
    for(i=0;i<n;i++)
        for(j=0;j<n;j++)
            if(i!=j)
            {
                k=0;
                for(p=0;p<l[i];p++)
                {
                    while(k>0 && sir[i][p]!=sir[j][k])
                        k=pref[j][k-1];
                    if(sir[i][p]==sir[j][k])
                        k++;
                    if(k==l[j])
                    {
                        elimin[j]=1;
                        //k=pref[j][k-1]; - nenecesar
                        break;
                    }
                }
                coresp[i][j]=k;
            }

    //Contabilizam siruirle ramase dupa eliminarile facute
    for(i=0;i<n;i++)
        if(!elimin[i])
            ram[poz++]=i;

    //Dinamica pe stari din[i][j] = cel mai scurt sir ce contine toate sirurile din configuratia binara a lui i si il are la sfarsit sirul j
    int aux;
    prec[0][0]=-1;
    for(i=1;i<(1<<(poz));i++) //For dupa stari, in ordine crescatoare a lor
    {
        for(j=0;j<poz;j++) //For dupa siruri
        {
            din[i][j]=INF;
            prec[i][j]=-1;

            if(i&(1<<j))
                for(k=0;k<poz;k++)
                    if(((i&(1<<k))!=0))
                    {
                        aux=din[i^(1<<j)][k]-coresp[ram[k]][ram[j]]+l[ram[j]];
                        if(din[i][j]>aux)
                            din[i][j]=aux,prec[i][j]=k;
                    }

            if((i&(i-1))==0) //Pentru starile putere de 2, prec-ul se va calcula gresit
                prec[i][j]=-1;
        }
    }

    //Aflam care sir trebuie sa fie la sfarsitul rezultatului (astfel incat lungimea totala sa fie minima
    int care=-1,mini=INF;
    for(i=0;i<poz;i++)
    {
        if(din[(1<<poz)-1][i]<mini)
            mini=din[(1<<poz)-1][i],care=i;
    }

    //In rasp vom pune, in ordine inversa a aparitiei lor in raspuns, sirurile ramase dupa eliminare (evident, doar indicii lor)
    int rasp[20],poz2=0;
    int stare=(1<<poz)-1,vechi=care;
    while(care>=0)
    {
        rasp[poz2++]=care;
        care=prec[stare][care];
        stare-=(1<<(vechi));
        vechi=care;
    }

    //Afisam sirul final
    afis(ram[rasp[poz2-1]],0);
    for(i=poz2-2;i>=0;i--)
        afis(ram[rasp[i]],coresp[ram[rasp[i+1]]][ram[rasp[i]]]);
    cout<<'\n';

    cin.close();
    cout.close();
    return 0;
}