Pagini recente » Cod sursa (job #239675) | Istoria paginii utilizator/georgie | Cod sursa (job #2945) | Profil M@2Te4i | Cod sursa (job #2962753)
// adn - https://infoarena.ro/job_detail/2962657?action=view-source
/*Nodurile:
X : C A A A A B C D E
Y : D E A C C C
Muchiile:
X -> Y : 2 (sf lui X cu în lui Y)
Y -> X : 1 (sf lui Y cu în lui X)
Caut o parcurgere a grafului astfel încât suma muchiilor sa fie maxima și fiecare nod parcurs o singura data
dp[i][conf] = suma maxima a muchiilor pana în i având vizitate nodurile din conf
dp[i][conf] = 0 (inițial)
Conf_nou += 1 << vec
dp[vec][conf_nou] = max(dp[vec][conf_nou], dp[i][conf] + muchie(i, vec))
For pt conf (de la 0 la 2^n -1)
For pt I (de la 0, la n - 1)
verify dacă i în conf
for(auto vec: ad[I])
verify faca vec nu e in conf
recurenta
*/
#include <iostream>
#include <fstream>
#include <climits>
#include <vector>
#include <algorithm>
using namespace std;
ifstream fin("adn.in");
ofstream fout("adn.out");
int n;
string adn[20];
int cost[20][20];
int dp[20][1 << 20];
vector<string> new_adn;
bool eliminated[20];
pair<int, int> father[20][1 << 20];
vector<int> path;
int p[30005];
// ------------------------------ Word Distance ---------------------------------
int wordDistance(int word1, int word2) {
// Calculez subsecventa comuna intre sfarsitul primului cuvant si inceputul celui de-al doilea cuavnt
string str1 = adn[word1];
string str2 = adn[word2];
int w_size1 = str1.size();
int w_size2 = str2.size();
for (int i = 0; i < w_size1; i++) {
// Verific suprapunerea de la pozitia i in dreapta
bool same = true;
for (int j = i; (j < w_size1) && (j - i < w_size2); j++) {
// Verific daca cele doua cuvinte sunt identice
if (str1[j] != str2[j - i]) {
same = false;
break;
}
}
if (same) {
// Verific daca al doilea cuvant se gaseste in interiorul primului
if (w_size1 - i >= w_size2) {
return -1;
}
// Lungimea comuna a celor doua cuvinte
return w_size1 - i;
}
}
// Cuvintele nu au litere in comun
return 0;
}
// ------------------------------ Remake ADN ---------------------------------
void remakeADN() {
new_adn.push_back("");
// Daca sunt mai multe cuvinte identice, lasa doar prima aparitie
for(int i = 1; i < n; i ++)
for(int j = i + 1; j <= n; j ++) {
if(adn[i] == adn[j])
eliminated[j] = true;
}
for(int i = 1; i < n ; i ++){
if(eliminated[i])
continue;
for(int j = 1; j <= n; j ++) {
if(i == j || eliminated[j])
continue;
if(wordDistance(i, j) == -1) {
eliminated[j] = true;
//cout << i << " " << j <<'\n';
} else
if(wordDistance(j, i) == -1) {
eliminated[i] = true;
//cout << j << " " << i << '\n';
}
}
}
for(int i = 1; i <= n; i ++)
if(!eliminated[i]) {
new_adn.push_back(adn[i]);
}
}
// ------------------------------ Main ---------------------------------
int main() {
// Citesc string-urile de adn
fin >> n;
for(int i = 1; i <= n; i ++)
fin >> adn[i];
// Refac vectorul de string-uri astfel incat sa elimin string-urile ce se regasesc in interiorul altora
remakeADN();
n = new_adn.size() - 1;
// Suprascriu adn cu new_adn
for(int i = 1; i <= n ; i ++)
adn[i] = new_adn[i];
// Calculez costul distantelor dintre cuvinte
for(int i = 0; i < n; i++)
for(int conf = 0; conf < (1 << n); conf++)
dp[i][conf] = -(1 << 30);
for(int i = 0; i < n; i++)
dp[i][(1 << i)] = 0;
for(int i = 1; i < n; i ++)
for(int j = i + 1; j <= n; j ++) {
cost[i][j] = wordDistance(i, j);
cost[j][i] = wordDistance(j, i);
}
// Caut o parcurgere a grafului astfel încât suma muchiilor sa fie maxima și fiecare nod parcurs o singura data
// dp[i][conf] = suma maxima a muchiilor pana în i având vizitate nodurile din conf
for(int conf = 0; conf <= (1 << n) - 1; conf ++)
for(int i = 0; i < n; i ++)
if(conf & (1 << i)) // Verific daca i este deja vizitat
for(int j = 0; j < n; j ++)
if(cost[i + 1][j + 1] != -1 && !(conf & (1 << j))) { // Verific daca j este vecini si daca nu este vizitat
if(dp[j][conf + (1 << j)] < dp[i][conf] + cost[i + 1][j + 1])
{
father[j][conf + (1 << j)] = make_pair(i, conf);
dp[j][conf + (1 << j)] = dp[i][conf] + cost[i + 1][j + 1];
}
// int new_conf = conf + (1 << j);
// if(dp[j][new_conf] < dp[i][conf] + cost[i + 1][j + 1])
// father[j][new_conf] = make_pair(i, conf);
// dp[j][new_conf] = max(dp[j][new_conf], dp[i][conf] + cost[i + 1][j + 1]);
}
int last_node = -1;
int max_size = -1;
// Caut maximul din dp[i][(1 << n> - 1]
for(int i = 0; i < n; i ++)
if(dp[i][(1 << n) - 1] > max_size) {
max_size = dp[i][(1 << n) - 1];
last_node = i;
}
int node = last_node;
int conf = (1 << n) - 1;
while(conf != 0) {
path.push_back(node + 1);
int new_conf = father[node][conf].second;
node = father[node][conf].first;
conf = new_conf;
}
reverse(path.begin(), path.end());
// Reconstituire sir
string result = "";
result += adn[path[0]];
for(int i = 1; i < path.size(); i ++) {
for(int j = cost[path[i - 1]][path[i]]; j < adn[path[i]].size(); j ++) {
result += adn[path[i]][j];
}
}
fout << result;
return 0;
}