Pagini recente » Cod sursa (job #2052044) | Rating Danaila Iulia (jdth) | Monitorul de evaluare | Cod sursa (job #4579) | Cod sursa (job #2962756)
// 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 max_length = 30000;
const int mod1 = 30103;
const int mod2 = 666013;
int suf_mod1[30005], suf_mod2[30005], pref_mod1[30005], pref_mod2[30005];
int pow26_mod1[30005], pow26_mod2[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;
//}
// -------------------------------- Rabin Karp --------------------------------------
void pow() {
// calculeaza puterile lui 26
pow26_mod1[0] = 1;
pow26_mod2[0] = 1;
for(int i = 1; i < max_length; i++)
{
pow26_mod1[i] = (pow26_mod1[i - 1] * 26) % mod1;
pow26_mod2[i] = (pow26_mod2[i - 1] * 26) % mod2;
}
}
int rabinKarp(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();
// Initializez vectorii
fill(suf_mod1, suf_mod1 + max_length + 1, 0);
fill(suf_mod2, suf_mod2 + max_length + 1, 0);
fill(pref_mod1, pref_mod1 + max_length + 1, 0);
fill(pref_mod2, pref_mod2 + max_length + 1, 0);
// pref_mod[i] = prefixul lui str1 pana la poz i
// suf_mod[i] = sufixul lui str2 de la poz i
// Transform primul caracter in numar
pref_mod1[0] = str2[0] - 'A';
pref_mod2[0] = str2[0] - 'A';
// Calculez restul prefixelor sirului str2
for(int i = 1; i < w_size2; i++)
{
pref_mod1[i] = (pref_mod1[i - 1] * 26 + str2[i] - 'A') % mod1;
pref_mod2[i] = (pref_mod2[i - 1] * 26 + str2[i] - 'A') % mod2;
}
// Calculez sufixele sirului str1
for(int i = w_size1 - 1; i >= 0; i--)
{
suf_mod1[i] = ((str1[i] - 'A') * pow26_mod1[w_size1 - i - 1] + suf_mod1[i + 1]) % mod1;
suf_mod2[i] = ((str1[i] - 'A') * pow26_mod2[w_size1 - i - 1] + suf_mod2[i + 1]) % mod2;
}
// Caut pozitia la care se suprapun
for(int i = 0; i < w_size1; i++)
{
if(w_size1 - i > w_size2)
continue;
if(suf_mod1[i] == pref_mod1[w_size1 - i - 1] && suf_mod2[i] == pref_mod2[w_size1 - i - 1])
{
if(w_size1 - i - 1 == w_size2 - 1) // str1 = str2
return -1;
return w_size1 - i; // str1 si str2 se suprapun
}
}
return 0; // str1 si str2 nu se suprapun
}
// ------------------------------ 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 (adn[i].find(adn[j]) != std::string::npos)
eliminated[j] = true;
}
}
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];
// Initializez dp[i][j]
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;
// Initializez puterile lui 26 pentru Rabin Karp
pow();
// Calculez costul distantelor dintre cuvinte
for(int i = 1; i < n; i ++)
for(int j = i + 1; j <= n; j ++) {
cost[i][j] = rabinKarp(i, j);
cost[j][i] = rabinKarp(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 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;
}