Pagini recente » Cod sursa (job #2955341) | Cod sursa (job #2790675) | Cod sursa (job #2318977) | Cod sursa (job #1845627) | Cod sursa (job #2961418)
#include<iostream>
#include<deque>
#include<algorithm>
#include<vector>
#include<fstream>
using namespace std;
ifstream in("adn.in");
ofstream out("adn.out");
const int mx = 18;
int n;
vector<string> v;
// dist[i][j] - the distance between the nodes i and j (the number of characters saved by merging string i and j)
int dist[mx][mx];
int newdist[mx][mx];
int back[mx];
// dp[node][mask] - the maximum cost of a path ending in node and passing through all nodes in mask.
int dp[mx][1<<mx];
// prv[node][mask] - the next to last node of the path that ends in node and connects all nodes in mask.
int prv[mx][1<<mx];
bool contained[mx];
void read(){
in>>n;
v.resize(n);
for(int i=0;i<n;i++){
in>>v[i];
}
}
// The number of characters that can be saved if the two strings are merged together.
// example : abcde merged by cdefg is abcdefg
// the cost is "fg" - 2
// The problem now becomes finding a path that maximizes the number of characters saved.
int cost(const string&a, const string&b){
// First compute the lsp of the second string.
// lsp(i) - the longest preffix that is also a suffix
// of the string formed by the first i+1 characters.
vector<int> lsp(b.length());
lsp[0] = 0;
int i = 0;
int j = 1;
while(j<b.length()){
if(b[i] == b[j]){
i++;
lsp[j] = i;
j++;
}
else{
if(i==0){
lsp[j] = 0;
j++;
}
else{
i = lsp[i-1];
}
}
}
int result = 0;
// Now compute kmp.
i = 0 ,j = 0;
while(i<a.length()){
if(a[i] == b[j]){
i++;
j++;
if(j==b.length())
return j;
}
else{
if(j==0){
i++;
}
else{
j = lsp[j-1];
}
}
}
return j;
}
void compute_distances1(){
for(int i=0;i<n;i++){
for(int k=0;k<n;k++){
if(i==k)
continue;
dist[i][k] = cost(v[i],v[k]);
if(dist[i][k] == v[k].length()){
contained[k] = true;
}
}
}
}
void compute_distances2(){
for(int i=0;i<n;i++){
for(int k=0;k<n;k++){
if(i==k)
continue;
newdist[i][k] = dist[back[i]][back[k]];
}
}
}
void solve(){
compute_distances1();
int correct = 0;
for(int i=0;i<n;i++){
if(!contained[i]){
back[correct] = i;
correct++;
}
}
n = correct;
compute_distances2();
int all = (1<<n) -1;
for(int mask = 0 ; mask<=all; mask++){
for(int ending=0;ending<n;ending++){
if((mask & (1<<ending)) == 0)
continue;
for(int previous=0;previous<n;previous++){
if(previous == ending)
continue;
if((mask & (1<<previous)) == 0)
continue;
int c = dp[previous][mask ^ (1<<ending)] + newdist[previous][ending];
if(dp[ending][mask] <= c){
dp[ending][mask] = c;
prv[ending][mask] = previous;
}
}
}
}
// Find the best node to end at.
int current = 0;
for(int i=0;i<n;i++){
if(dp[current][all]<dp[i][all]){
current = i;
}
}
// Rebuild path.
vector<int> path;
int mask = all;
while(mask!=0){
path.push_back(current);
int prev_mask = mask ^ (1<<current);
int prev_node = prv[current][mask];
current = prev_node;
mask = prev_mask;
}
reverse(path.begin(),path.end());
int skip_next = 0;
for(int i=0;i<n;i++){
int node = path[i];
string s = v[back[node]].substr(skip_next);
out<<s;
if(i!=n-1){
skip_next = newdist[node][path[i+1]];
}
}
}
int main(){
read();
solve();
return 0;
}