Pagini recente » Cod sursa (job #2888464) | Cod sursa (job #1842885) | Cod sursa (job #996375) | Cod sursa (job #2713145) | Cod sursa (job #1009271)
#include <fstream>
#include <cstring>
#include <bitset>
using namespace std;
char sir[18][30005];
int pref[18][30005];
int din[262200][18];
int prec[262200][18];
int l[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;
int coresp[18][18];
for(i=0;i<18;i++)
for(j=0;j<18;j++)
coresp[i][j]=0;
int ram[18];
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;
}