Cod sursa(job #81142)

Utilizator VmanDuta Vlad Vman Data 31 august 2007 16:53:46
Problema ADN Scor 20
Compilator cpp Status done
Runda Arhiva de probleme Marime 3.19 kb
using namespace std;
#include <stdio.h>
#include <string.h>
#include <vector>

#define Nmax 18
#define Lmax 30001
#define cardinal 1<<18

int N, i, j, ban=0, banned=0;
int T[Lmax], g[Nmax][Nmax];
int A[Nmax][cardinal],Ant[Nmax][cardinal];
char s[Nmax][Lmax];
vector<int> M[Nmax+1];

void submultimi(int nr, int card)
{
 int i, p;
 M[card].push_back(nr);
 if (card == N - banned) return;
 ++card;
 for (i=0,p=1; i<N; ++i,p<<=1)
     if ((p ^ nr) > nr) submultimi(nr+p, card);
}

void init()
{
 int i, p;
 for (i=0,p=1; i<N; ++i,p<<=1)
     if ((p ^ ban) > ban) submultimi(ban + p, 1);
}

void citire()
{
 freopen("adn.in", "r", stdin);
 scanf("%d", &N);
 for (i=0; i<N; ++i)
     scanf("%s", &s[i]);
 fclose(stdin);
}

void prefix(int indice)
{
 int i = 2, j = 0, lungime = strlen( s[indice] );
 while (i <= lungime)
        if (s[indice][i-1] == s[indice][j])
            T[i++] = j++;
            else if (j>0) j = T[j];
                 else T[i++] = 0;
}

int KMP(int sursa, int subsir)
{
 int i = 0, j = 0, l1 = strlen( s[sursa] ), l2 = strlen( s[subsir] );
 while (i + j < l1)
       {
        if (s[sursa][i+j] == s[subsir][j])
           {
            ++j;
            if (j == l2) {
                          ++banned;
                          ban+=(1<<subsir);
                          return -1; //potrivire completa
                         }
           }
           else
           {
            i = i + j - T[j];
            if (j > 0) j = T[j];
           }
       }
 return j; //ultimele j caractere din sursa corespund primelor j din subsir
}

void hamiltonian_cycle()
{
 vector<int>::iterator it;
 int i, j, p, jj, pp;
 //programare dinamica
 for (i=0,p=1; i<N; ++i,p<<=1)
     if ((p^ban)>ban)
        {
        A[i][p^ban]=1;
        Ant[i][p^ban]=-1;
        }
 for (i=1; i<N-banned; ++i)
     for (it=M[i].begin(); it<M[i].end(); ++it)
         for (j=0,p=1; j<N; ++j,p<<=1)
             if ((p ^ (*it - ban)) < (*it - ban))
                for (jj=0,pp=1; jj<N; ++jj,pp<<=1)
                    if ( ((pp ^ (*it)) > *it) && (A[jj][pp ^ *it] < A[j][*it] + g[j][jj]) )
                       {
                        A[jj][pp ^ *it] = A[j][*it] + g[j][jj];
                        Ant[jj][pp ^ *it] = j;
                       }
}

void solutie()
{
 int i, max, p = (1<<N)-1, pp;
 max=0;
 for (i=1; i<N; ++i)
     if (A[i][p] > A[max][p]) max = i;
 freopen("adn.out","w",stdout);
 while (Ant[max][p] != -1)
       {
        pp = strlen(s[max]) - g[Ant[max][p]][max];
        for (i=0; i<pp; ++i)
           printf("%c", s[max][i]);
        pp = p;
        p -= (1 << max);
        max = Ant[max][pp];
       }
 printf("%s",s[max]);
 fclose(stdout);
}

int main()
{
 citire();
 T[0] = -1;
 T[1] = 0;
 //muchiile sunt retinute in sens invers ca sa nu rup linia de cache cu for-u
 //g[i][j] = costul arcului de la j la i
 //astfel rezultatul va fi afisat in ordine inversa dupa indici
 for (i=0; i<N; ++i)
     {
      prefix(i);
      for (j=0; j<i; ++j)
          g[i][j] = KMP(j, i);
      for (j=i+1; j<N; ++j)
          g[i][j] = KMP(j, i);
     }
 init();
 hamiltonian_cycle();
 solutie();
 return 0;
}