Pagini recente » Cod sursa (job #577540) | Cod sursa (job #1781946) | Cod sursa (job #749037) | Monitorul de evaluare | Cod sursa (job #1024435)
#include <fstream>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
int n, Pi[60100], ns[20], cost[20][20], best[18][263000], Next[18][263000], sol;
char s[20][30100], concat[60100];
bool eliminat[20];
string S[20];
inline void CreateGraph()
{
int i, j, k, p;
// elimin cuvintele incluse in alte cuvinte
for( i = 0; i < n; ++i)
{
for( j = i + 1; j < n && !eliminat[i]; ++j)
{
memset(Pi, 0, sizeof(Pi));
Pi[1] = 0;
k = 0;
for( p = 2; p <= ns[i]; ++p)
{
while( k && s[i][k + 1] != s[i][p]) k = Pi[k];
if(s[i][k + 1] == s[i][p]) k++;
Pi[p] = k;
}
k = 0;
for( p = 1; p <= ns[j]; ++p)
{
while(k && s[i][k + 1] != s[j][p]) k=Pi[k];
if(s[i][k + 1] == s[j][p]) k++;
if(k == ns[i])
{
eliminat[i]=true;
p=ns[j];
}
}
}
}
// calculez cel mai lung sufix al unui cuvant care este prefix al altuia
for( i = 0; i < n; ++i)
{
if(eliminat[i])
continue;
for( j = 0; j < n; ++j)
{
if(eliminat[j])
continue;
memset(Pi, 0, sizeof(Pi));
for( k = 1; k <= ns[j]; ++k)
concat[k] = s[j][k];
for( k = 1; k <= ns[i]; ++k)
concat[ns[j] + k] = s[i][k];
Pi[1] = 0;
k = 0;
for( p = 2; p <= ns[i] + ns[j]; ++p)
{
while( k && concat[k + 1] != concat[p]) k = Pi[k];
if(concat[k + 1] == concat[p]) k++;
Pi[p] = k;
}
cost[i][j] = Pi[ns[i] + ns[j]];
}
}
}
inline string FindSecv()
{
int i, j, conf, first, aux, conflim = 0;
string rez;
// initializez matricea cu INF
for( conf = 0; conf < (1<<n); ++conf)
{
for( i = 0; i < n; ++i)
{
best[i][conf] = 1000000000;
Next[i][conf] = -1;
}
}
// asta va fi configuratia finala
for( i = 0; i < n; ++i)
if(!eliminat[i])
conflim += (1 << i);
// initializez starile initiale
for( i = 0; i < n; ++i)
if(!eliminat[i])
best[i][( 1 << i)] = ns[i];
// fac dinamica pentru lant hamiltonian de cost minim
for( conf = 0; conf < (1<<n); ++conf)
{
for( i = 0; i < n; ++i)
{
if(eliminat[i])
continue;
if(conf & (1 << i))
{
for( j = 0; j < n; ++j)
{
if(eliminat[j])
continue;
if(!(conf & (1 << j)))
{
if(best[j][conf + (1 << j)] > ns[j] - cost[j][i] + best[i][conf])
{
best[j][conf + (1 << j)] = ns[j] - cost[j][i] + best[i][conf];
Next[j][conf + (1 << j)] = i;
}
}
}
}
}
}
// determin nodul de start din lant
first = -1;
sol = 1000000000;
for( i = 0; i < n; ++i)
{
if(eliminat[i])
continue;
if(best[i][conflim] < sol)
{
sol = best[i][conflim];
first = i;
}
}
// construiesc secventa ADN care va fi solutie
for( i = 1; i <= ns[first]; ++i)
rez += s[first][i];
conf = conflim;
while(Next[first][conf] != -1)
{
aux = first;
first = Next[first][conf];
conf -= (1 << aux);
for( i = cost[aux][first] + 1; i <= ns[first]; ++i)
rez += s[first][i];
}
return rez;
}
inline bool Sortare(string a, string b)
{
if(a.size() < b.size())
return true;
if(a.size() > b.size())
return false;
if(a.compare(b)<=0)
return true;
return false;
}
int main()
{
int i, j;
ifstream fin("adn.in");
fin >> n;
for(i = 0; i < n; ++i)
fin >> S[i];
fin.close();
// sortez sirurile lexicografic
sort(S, S + n, Sortare);
for(i = 0; i < n; ++i)
{
ns[i] = S[i].size();
for(j = 0; j < ns[i]; ++j)
s[i][j + 1]= S[i][j];
}
CreateGraph();
ofstream fout("adn.out");
fout << FindSecv() << "\n";
fout.close();
return 0;
}