Pagini recente » Cod sursa (job #2932718) | Cod sursa (job #1135975) | Cod sursa (job #65071) | Cod sursa (job #2532988) | Cod sursa (job #2960283)
#include <fstream>
#include <string>
#include <vector>
#include <algorithm>
#include <map>
using namespace std;
const int INF = (1 << 30);
vector <int> kmp(string s, string t) {
string w = s + "." + t;
vector <int> pi(w.size(), 0);
for (int i = 1, k = 0; i < w.size(); ++i) {
while (k > 0 && w[i] != w[k])
k = pi[k - 1];
if (w[i] == w[k])
++k;
pi[i] = k;
}
return pi;
}
bool is_substr(string s, string t) {
vector <int> pi = kmp(s, t);
return find(pi.begin(), pi.end(), s.size()) != pi.end();
}
int main() {
ifstream fin("adn.in");
ofstream fout("adn.out");
int N;
fin >> N;
vector <string> input_words(N);
for (int i = 0; i < N; ++i) {
fin >> input_words[i];
}
// Elimin duplicatele.
vector <string> words;
sort(input_words.begin(), input_words.end());
for (int i = 0, j = 0; i < input_words.size(); i = j) {
while (j < input_words.size() && input_words[i] == input_words[j]) {
++j;
}
words.push_back(input_words[i]);
}
input_words = words;
words.clear();
// Elimin cuvintele useless i.e. cuvinte care sunt substring-uri ale altor cuvinte.
N = input_words.size();
for (int i = 0; i < N; ++i) {
bool ok = true;
for (int j = 0; j < N && ok; ++j) {
if (i != j && is_substr(input_words[i], input_words[j])) {
ok = false;
}
}
if (ok) {
words.push_back(input_words[i]);
}
}
N = words.size();
vector <vector <int> > cost(N, vector <int>(N, 0));
for (int i = 0; i < N; ++i) {
for (int j = 0; j < N; ++j) {
if (i != j) {
cost[i][j] = kmp(words[i], words[j]).back();
}
}
}
vector <vector <int> > dp(N, vector <int>((1 << N), -INF));
vector <vector <pair <int, int> > > prev(N, vector <pair <int, int> >((1 << N)));
// Hamilton
for (int i = 0; i < N; ++i) {
dp[i][1 << i] = 0;
prev[i][1 << i] = make_pair(-1, 0);
}
for (int mask = 1; mask < (1 << N); ++mask) {
for (int i = 0; i < N; ++i) {
if (mask & (1 << i)) {
for (int j = 0; j < N; ++j) {
if (!(mask & (1 << j))) {
int new_mask = mask | (1 << j);
if (dp[i][mask] + cost[j][i] > dp[j][new_mask]) {
dp[j][new_mask] = dp[i][mask] + cost[j][i];
prev[j][new_mask] = make_pair(i, mask);
}
}
}
}
}
}
int best = -INF;
int pos = -1;
for (int i = 0; i < N; ++i) {
if (dp[i][(1 << N) - 1] > best) {
best = dp[i][(1 << N) - 1];
pos = i;
}
}
vector <int> words_order;
int mask = (1 << N) - 1;
while (pos != -1) {
words_order.push_back(pos);
int new_pos = prev[pos][mask].first;
mask = prev[pos][mask].second;
pos = new_pos;
}
reverse(words_order.begin(), words_order.end());
string answer = words[words_order[0]];
for (int i = 1; i < N; ++i) {
int c = cost[words_order[i]][words_order[i - 1]];
answer += words[words_order[i]].substr(c);
}
fout << answer << "\n";
fin.close();
fout.close();
return 0;
}