Pagini recente » Cod sursa (job #3228719) | Cod sursa (job #2875376) | Cod sursa (job #2414620) | Cod sursa (job #682207) | Cod sursa (job #2962001)
#include <iostream>
#include <fstream>
#include <vector>
#include <stdio.h>
#include <string.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.emplace_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;
}