Pagini recente » Cod sursa (job #489440) | Monitorul de evaluare | Cod sursa (job #2673746) | Cod sursa (job #262155) | Cod sursa (job #2634468)
#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)
{
if(mask==0) return;
int nodant=dp2[nod][mask], maskant=mask-(1<<nod), folosite=b[nodant].size()-(dp[nod][mask]-dp[nodant][maskant]);
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=0, maxi=0;
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;
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;
}