#include <iostream>
#include <random>
#include <set>
#include <algorithm>
using namespace std;
random_device rd;
mt19937 gen(rd());
const int TL = 100, PROB_DE_OCORRENCIA = 2, PRIZE = 400;
int get_row_size(int N);
int get_col_size(int M);
vector<vector<int>> create_graph(int N, int M);
int get_evaluation(vector<vector<int>> graph, vector<pair<int, int>> solution);
vector<vector<pair<int, int>>> genetic(vector<vector<int>> graph, int N, int M);
vector<pair<int, int>> get_random_solution(int N, int M);
pair<vector<pair<int, int>>, vector<pair<int, int>>> choose_parents(vector<vector<pair<int, int>>> population);
vector<pair<int, int>> get_free_connections(vector<vector<int>> incomplete_graph, int N, int M);
pair<vector<pair<int, int>>, vector<pair<int, int>>> crossover(vector<vector<pair<int, int>>> parents, int N, int M);
vector<pair<int, int>> mutate(vector<pair<int, int>> solution, int N, int M);
int main() {
int N = 5, M = 5;
vector<vector<int>> graph = create_graph(N, M);
for(int i = 0, par = 2; i < N; ++i, par += 2) {
for(int j = 0, impar = 1; j < M; ++j, impar += 2) {
cout<<graph[par][impar]<<' ';
}
cout<<'\n';
}
vector<vector<pair<int, int>>> ans = genetic(graph, N, M);
int count = 0;
for(vector<pair<int, int>> v : ans) {
cout<<"Solution "<<++count<<':'<<'\n';
for(pair<int, int> vv : v) {
cout<<vv.first<<' '<<vv.second<<'\n';
}
cout<<'\n';
}
return 0;
}
int get_row_size(int N) {
return 3 * N + 5;
}
int get_col_size(int M) {
return 3 * M + 5;
}
vector<vector<int>> create_graph(int N, int M) {
vector<vector<int>> graph(get_row_size(N), vector<int>(get_col_size(M)));
uniform_int_distribution<> get_random(1, 100);
for(int i = 0, par = 2; i < N; ++i, par += 2) {
for(int j = 0, impar = 1; j < M; ++j, impar += 2) {
graph[par][impar] = get_random(gen);
}
}
return graph;
}
int get_evaluation(vector<vector<int>> graph, vector<pair<int, int>> solution) {
int somatorio_dos_pesos = 0;
set<int> vertices;
for(auto [vertice1, vertice2] : solution) {
somatorio_dos_pesos += graph[vertice1][vertice2];
vertices.emplace(vertice1), vertices.emplace(vertice2);
}
const int numero_de_vertices = vertices.size();
return numero_de_vertices * PRIZE - somatorio_dos_pesos;
}
vector<vector<pair<int, int>>> genetic(vector<vector<int>> graph, int N, int M) {
uniform_int_distribution<> get_random(1, 100);
const int MAX = 5 * max(N, M);
const int HALF = MAX / 2;
vector<vector<pair<int, int>>> generation;
for(int i = 0; i <= MAX; ++i) {
generation.push_back( get_random_solution(N, M) );
}
for(int i = 1, t = 1; t < TL; ++i, ++t) {
for(int j = 1; j <= HALF; ++j) {
const auto [parent1, parent2] = choose_parents( generation );
const vector<vector<pair<int, int>>> parents = {parent1, parent2};
auto [child1, child2] = crossover(parents, N, M);
// auto [child1, child2] = pair<vector<pair<int, int>>, vector<pair<int, int>>>{parents[0], parents[1]};
if(get_random(gen) < PROB_DE_OCORRENCIA) {
child1 = mutate(child1, N, M);
}
if(get_random(gen) < PROB_DE_OCORRENCIA) {
child2 = mutate(child2, N, M);
}
generation.push_back(child1);
generation.push_back(child2);
}
const auto sort_comparator = [&](vector<pair<int, int>> a, vector<pair<int, int>> b) -> bool {
return get_evaluation(graph, a) > get_evaluation(graph, b);
};
sort(generation.begin(), generation.end(), sort_comparator);
generation.resize( MAX );
}
return generation;
}
vector<pair<int, int>> get_random_solution(int N, int M) {
vector<pair<int, int>> solution;
vector<int> free_verticesN, free_verticesM, vertex_used(max(get_row_size(N), get_col_size(M)), 0);
for(int i = 1, val = 2; i < N; ++i, val += 2) {
free_verticesN.push_back(val);
}
for(int i = 0, val = 1; i < M; ++i, val += 2) {
free_verticesM.push_back(val);
}
for(int i = 1; i <= min(N, M); ++i) {
uniform_int_distribution<> N_get_random(0, free_verticesN.size()-1);
uniform_int_distribution<> M_get_random(0, free_verticesM.size()-1);
const int random_index_n = N_get_random(gen);
const int random_index_m = M_get_random(gen);
const int vertex1 = free_verticesN[random_index_n];
const int vertex2 = free_verticesM[random_index_m];
solution.push_back({ vertex1, vertex2 });
vertex_used[vertex1]++;
vertex_used[vertex2]++;
if(vertex_used[vertex1] == 2) free_verticesN.erase(free_verticesN.begin() + random_index_n);
if(vertex_used[vertex2] == 2) free_verticesM.erase(free_verticesM.begin() + random_index_m);
}
return solution;
}
pair<vector<pair<int, int>>, vector<pair<int, int>>> choose_parents(vector<vector<pair<int, int>>> population) {
uniform_int_distribution<> get_random(0, population.size() - 1);
const int rand_parent1 = get_random(gen);
const int rand_parent2 = get_random(gen);
return { population[rand_parent1], population[rand_parent2] };
}
vector<pair<int, int>> get_free_connections(vector<vector<int>> incomplete_graph, int N, int M) {
vector<pair<int, int>> free_connections;
for(int i = 0, par = 2; i < N; ++i, par += 2) {
for(int j = 0, impar = 1; j < M; ++j, impar += 2) {
if(incomplete_graph[i][j] == false) {
free_connections.emplace_back(par, impar);
}
}
}
return free_connections;
}
pair<vector<pair<int, int>>, vector<pair<int, int>>> crossover(vector<vector<pair<int, int>>> parents, int N, int M) {
//// Child 1 = Half(Parent1) + Half2(Parent2)
//// Child 2 = Half(Parent2) + Half2(Parent1)
// probabilidade de troca = 50%;
uniform_int_distribution<> get_random(0, 1);
const int swap_ = get_random(gen);
if(swap_) {
swap(parents[0], parents[1]);
}
vector<vector<vector<int>>> graph(2, vector<vector<int>>(get_row_size(N), vector<int>(get_col_size(M), false)));
vector<vector<pair<int, int>>> connections(2);
int num_of_connections[2] = {0};
const int HALF = min(N, M) / 2;
for(int i = 0; i < HALF; ++i) {
for(int parent = 0; parent < 2; ++parent) {
const auto [vertex1, vertex2] = parents[parent][i];
const int child = parent;
graph[child][vertex1][vertex2] = true;
connections[child].emplace_back(vertex1, vertex2);
++num_of_connections[child];
}
}
for(int i = HALF; i < min(N, M); ++i) {
for(int parent = 0; parent < 2; ++parent) {
const auto [vertex1, vertex2] = parents[parent][i];
const int child = parent;
if(graph[child][vertex1][vertex2] == false) {
graph[child][vertex1][vertex2] = true;
connections[child].emplace_back(vertex1, vertex2);
++num_of_connections[child];
}
}
}
vector<pair<int, int>> free_connections[2];
free_connections[0] = get_free_connections(graph[0], N, M);
free_connections[1] = get_free_connections(graph[1], N, M);
for(int child = 0; child < 2; ++child) {
vector<int> vertex_used(max(get_row_size(N), get_col_size(M)));
while(num_of_connections[child] < min(N, M)) {
uniform_int_distribution<> get_random_index(0, free_connections[child].size()-1);
int random_index, vertex1, vertex2;
bool valid_edge = false;
while(valid_edge == false) {
random_index = get_random_index(gen);
pair<int, int> vertices = free_connections[child][random_index];
vertex1 = vertices.first, vertex2 = vertices.second;
if(vertex_used[vertex1] == false && vertex_used[vertex2] == false) {
connections[child].emplace_back(free_connections[child][random_index]);
valid_edge = true;
++num_of_connections[child];
}
free_connections[child].erase(free_connections[child].begin() + random_index);
}
}
}
return pair<vector<pair<int, int>>, vector<pair<int, int>>>(connections[0], connections[1]);
}
vector<pair<int, int>> mutate(vector<pair<int, int>> solution, int N, int M) {
vector<vector<int>> graph(get_row_size(N), vector<int>(get_col_size(M), false));
for(auto [vertex1, vertex2] : solution) {
graph[vertex1][vertex2] = true;
}
vector<pair<int, int>> free_edges = get_free_connections(graph, N, M);
uniform_int_distribution<> get_random_index_of_used_edges(0, solution.size()-1);
uniform_int_distribution<> get_random_index_of_free_edges(0, free_edges.size()-1);
const int random_index_of_used_edges = get_random_index_of_used_edges(gen);
const int random_index_of_free_edges = get_random_index_of_free_edges(gen);
solution.erase(solution.begin() + random_index_of_used_edges);
solution.emplace_back(free_edges[random_index_of_free_edges]);
return solution;
}
I2luY2x1ZGUgPGlvc3RyZWFtPgojaW5jbHVkZSA8cmFuZG9tPgojaW5jbHVkZSA8c2V0PgojaW5jbHVkZSA8YWxnb3JpdGhtPgoKdXNpbmcgbmFtZXNwYWNlIHN0ZDsKCnJhbmRvbV9kZXZpY2UgcmQ7Cm10MTk5MzcgZ2VuKHJkKCkpOwoKY29uc3QgaW50IFRMID0gMTAwLCBQUk9CX0RFX09DT1JSRU5DSUEgPSAyLCBQUklaRSA9IDQwMDsKCmludCBnZXRfcm93X3NpemUoaW50IE4pOwppbnQgZ2V0X2NvbF9zaXplKGludCBNKTsKdmVjdG9yPHZlY3RvcjxpbnQ+PiBjcmVhdGVfZ3JhcGgoaW50IE4sIGludCBNKTsKaW50IGdldF9ldmFsdWF0aW9uKHZlY3Rvcjx2ZWN0b3I8aW50Pj4gZ3JhcGgsIHZlY3RvcjxwYWlyPGludCwgaW50Pj4gc29sdXRpb24pOwp2ZWN0b3I8dmVjdG9yPHBhaXI8aW50LCBpbnQ+Pj4gZ2VuZXRpYyh2ZWN0b3I8dmVjdG9yPGludD4+IGdyYXBoLCBpbnQgTiwgaW50IE0pOwp2ZWN0b3I8cGFpcjxpbnQsIGludD4+IGdldF9yYW5kb21fc29sdXRpb24oaW50IE4sIGludCBNKTsKcGFpcjx2ZWN0b3I8cGFpcjxpbnQsIGludD4+LCB2ZWN0b3I8cGFpcjxpbnQsIGludD4+PiBjaG9vc2VfcGFyZW50cyh2ZWN0b3I8dmVjdG9yPHBhaXI8aW50LCBpbnQ+Pj4gcG9wdWxhdGlvbik7CnZlY3RvcjxwYWlyPGludCwgaW50Pj4gZ2V0X2ZyZWVfY29ubmVjdGlvbnModmVjdG9yPHZlY3RvcjxpbnQ+PiBpbmNvbXBsZXRlX2dyYXBoLCBpbnQgTiwgaW50IE0pOwpwYWlyPHZlY3RvcjxwYWlyPGludCwgaW50Pj4sIHZlY3RvcjxwYWlyPGludCwgaW50Pj4+IGNyb3Nzb3Zlcih2ZWN0b3I8dmVjdG9yPHBhaXI8aW50LCBpbnQ+Pj4gcGFyZW50cywgaW50IE4sIGludCBNKTsKdmVjdG9yPHBhaXI8aW50LCBpbnQ+PiBtdXRhdGUodmVjdG9yPHBhaXI8aW50LCBpbnQ+PiBzb2x1dGlvbiwgaW50IE4sIGludCBNKTsKCmludCBtYWluKCkgewogIGludCBOID0gNSwgTSA9IDU7CgogIHZlY3Rvcjx2ZWN0b3I8aW50Pj4gZ3JhcGggPSBjcmVhdGVfZ3JhcGgoTiwgTSk7CiAgZm9yKGludCBpID0gMCwgcGFyID0gMjsgaSA8IE47ICsraSwgcGFyICs9IDIpIHsKICAgIGZvcihpbnQgaiA9IDAsIGltcGFyID0gMTsgaiA8IE07ICsraiwgaW1wYXIgKz0gMikgewogICAgICBjb3V0PDxncmFwaFtwYXJdW2ltcGFyXTw8JyAnOwogICAgfQogICAgY291dDw8J1xuJzsKICB9CiAgdmVjdG9yPHZlY3RvcjxwYWlyPGludCwgaW50Pj4+IGFucyA9IGdlbmV0aWMoZ3JhcGgsIE4sIE0pOwogIGludCBjb3VudCA9IDA7CiAgZm9yKHZlY3RvcjxwYWlyPGludCwgaW50Pj4gdiA6IGFucykgewogICAgY291dDw8IlNvbHV0aW9uICI8PCsrY291bnQ8PCc6Jzw8J1xuJzsKICAgIGZvcihwYWlyPGludCwgaW50PiB2diA6IHYpIHsKICAgICAgY291dDw8dnYuZmlyc3Q8PCcgJzw8dnYuc2Vjb25kPDwnXG4nOwogICAgfQogICAgY291dDw8J1xuJzsKICB9CgogIHJldHVybiAwOwp9CgppbnQgZ2V0X3Jvd19zaXplKGludCBOKSB7CiAgcmV0dXJuIDMgKiBOICsgNTsKfQoKaW50IGdldF9jb2xfc2l6ZShpbnQgTSkgewogIHJldHVybiAzICogTSArIDU7Cn0KCnZlY3Rvcjx2ZWN0b3I8aW50Pj4gY3JlYXRlX2dyYXBoKGludCBOLCBpbnQgTSkgewogIHZlY3Rvcjx2ZWN0b3I8aW50Pj4gZ3JhcGgoZ2V0X3Jvd19zaXplKE4pLCB2ZWN0b3I8aW50PihnZXRfY29sX3NpemUoTSkpKTsKICB1bmlmb3JtX2ludF9kaXN0cmlidXRpb248PiBnZXRfcmFuZG9tKDEsIDEwMCk7CiAgZm9yKGludCBpID0gMCwgcGFyID0gMjsgaSA8IE47ICsraSwgcGFyICs9IDIpIHsKICAgIGZvcihpbnQgaiA9IDAsIGltcGFyID0gMTsgaiA8IE07ICsraiwgaW1wYXIgKz0gMikgewogICAgICBncmFwaFtwYXJdW2ltcGFyXSA9IGdldF9yYW5kb20oZ2VuKTsKICAgIH0KICB9CiAgcmV0dXJuIGdyYXBoOwp9CgppbnQgZ2V0X2V2YWx1YXRpb24odmVjdG9yPHZlY3RvcjxpbnQ+PiBncmFwaCwgdmVjdG9yPHBhaXI8aW50LCBpbnQ+PiBzb2x1dGlvbikgewogIGludCBzb21hdG9yaW9fZG9zX3Blc29zID0gMDsKICBzZXQ8aW50PiB2ZXJ0aWNlczsKICBmb3IoYXV0byBbdmVydGljZTEsIHZlcnRpY2UyXSA6IHNvbHV0aW9uKSB7CiAgICBzb21hdG9yaW9fZG9zX3Blc29zICs9IGdyYXBoW3ZlcnRpY2UxXVt2ZXJ0aWNlMl07CiAgICB2ZXJ0aWNlcy5lbXBsYWNlKHZlcnRpY2UxKSwgdmVydGljZXMuZW1wbGFjZSh2ZXJ0aWNlMik7CiAgfQogIGNvbnN0IGludCBudW1lcm9fZGVfdmVydGljZXMgPSB2ZXJ0aWNlcy5zaXplKCk7CiAgcmV0dXJuIG51bWVyb19kZV92ZXJ0aWNlcyAqIFBSSVpFIC0gc29tYXRvcmlvX2Rvc19wZXNvczsKfQoKdmVjdG9yPHZlY3RvcjxwYWlyPGludCwgaW50Pj4+IGdlbmV0aWModmVjdG9yPHZlY3RvcjxpbnQ+PiBncmFwaCwgaW50IE4sIGludCBNKSB7CiAgdW5pZm9ybV9pbnRfZGlzdHJpYnV0aW9uPD4gZ2V0X3JhbmRvbSgxLCAxMDApOwogIGNvbnN0IGludCBNQVggPSA1ICogbWF4KE4sIE0pOwogIGNvbnN0IGludCBIQUxGID0gTUFYIC8gMjsKCiAgdmVjdG9yPHZlY3RvcjxwYWlyPGludCwgaW50Pj4+IGdlbmVyYXRpb247CiAgZm9yKGludCBpID0gMDsgaSA8PSBNQVg7ICsraSkgewogICAgZ2VuZXJhdGlvbi5wdXNoX2JhY2soIGdldF9yYW5kb21fc29sdXRpb24oTiwgTSkgKTsKICB9CiAgZm9yKGludCBpID0gMSwgdCA9IDE7IHQgPCBUTDsgKytpLCArK3QpIHsKICAgIGZvcihpbnQgaiA9IDE7IGogPD0gSEFMRjsgKytqKSB7CiAgICAgIGNvbnN0IGF1dG8gW3BhcmVudDEsIHBhcmVudDJdID0gY2hvb3NlX3BhcmVudHMoIGdlbmVyYXRpb24gKTsKICAgICAgY29uc3QgdmVjdG9yPHZlY3RvcjxwYWlyPGludCwgaW50Pj4+IHBhcmVudHMgPSB7cGFyZW50MSwgcGFyZW50Mn07CiAgICAgIGF1dG8gW2NoaWxkMSwgY2hpbGQyXSA9IGNyb3Nzb3ZlcihwYXJlbnRzLCBOLCBNKTsKICAgICAgLy8gYXV0byBbY2hpbGQxLCBjaGlsZDJdID0gcGFpcjx2ZWN0b3I8cGFpcjxpbnQsIGludD4+LCB2ZWN0b3I8cGFpcjxpbnQsIGludD4+PntwYXJlbnRzWzBdLCBwYXJlbnRzWzFdfTsKCiAgICAgIGlmKGdldF9yYW5kb20oZ2VuKSA8IFBST0JfREVfT0NPUlJFTkNJQSkgewogICAgICAgIGNoaWxkMSA9IG11dGF0ZShjaGlsZDEsIE4sIE0pOwogICAgICB9CiAgICAgIGlmKGdldF9yYW5kb20oZ2VuKSA8IFBST0JfREVfT0NPUlJFTkNJQSkgewogICAgICAgIGNoaWxkMiA9IG11dGF0ZShjaGlsZDIsIE4sIE0pOwogICAgICB9CiAgICAgIGdlbmVyYXRpb24ucHVzaF9iYWNrKGNoaWxkMSk7CiAgICAgIGdlbmVyYXRpb24ucHVzaF9iYWNrKGNoaWxkMik7CiAgICB9CgogICAgY29uc3QgYXV0byBzb3J0X2NvbXBhcmF0b3IgPSBbJl0odmVjdG9yPHBhaXI8aW50LCBpbnQ+PiBhLCB2ZWN0b3I8cGFpcjxpbnQsIGludD4+IGIpIC0+IGJvb2wgewogICAgICByZXR1cm4gZ2V0X2V2YWx1YXRpb24oZ3JhcGgsIGEpID4gZ2V0X2V2YWx1YXRpb24oZ3JhcGgsIGIpOwogICAgfTsKCiAgICBzb3J0KGdlbmVyYXRpb24uYmVnaW4oKSwgZ2VuZXJhdGlvbi5lbmQoKSwgc29ydF9jb21wYXJhdG9yKTsKICAgIAogICAgZ2VuZXJhdGlvbi5yZXNpemUoIE1BWCApOwogIH0KICByZXR1cm4gZ2VuZXJhdGlvbjsKfQoKdmVjdG9yPHBhaXI8aW50LCBpbnQ+PiBnZXRfcmFuZG9tX3NvbHV0aW9uKGludCBOLCBpbnQgTSkgewogIHZlY3RvcjxwYWlyPGludCwgaW50Pj4gc29sdXRpb247CiAgdmVjdG9yPGludD4gZnJlZV92ZXJ0aWNlc04sIGZyZWVfdmVydGljZXNNLCB2ZXJ0ZXhfdXNlZChtYXgoZ2V0X3Jvd19zaXplKE4pLCBnZXRfY29sX3NpemUoTSkpLCAwKTsKCiAgZm9yKGludCBpID0gMSwgdmFsID0gMjsgaSA8IE47ICsraSwgdmFsICs9IDIpIHsKICAgIGZyZWVfdmVydGljZXNOLnB1c2hfYmFjayh2YWwpOwogIH0KICBmb3IoaW50IGkgPSAwLCB2YWwgPSAxOyBpIDwgTTsgKytpLCB2YWwgKz0gMikgewogICAgZnJlZV92ZXJ0aWNlc00ucHVzaF9iYWNrKHZhbCk7CiAgfQoKICBmb3IoaW50IGkgPSAxOyBpIDw9IG1pbihOLCBNKTsgKytpKSB7CiAgICB1bmlmb3JtX2ludF9kaXN0cmlidXRpb248PiBOX2dldF9yYW5kb20oMCwgZnJlZV92ZXJ0aWNlc04uc2l6ZSgpLTEpOwogICAgdW5pZm9ybV9pbnRfZGlzdHJpYnV0aW9uPD4gTV9nZXRfcmFuZG9tKDAsIGZyZWVfdmVydGljZXNNLnNpemUoKS0xKTsKICAgIGNvbnN0IGludCByYW5kb21faW5kZXhfbiA9IE5fZ2V0X3JhbmRvbShnZW4pOwogICAgY29uc3QgaW50IHJhbmRvbV9pbmRleF9tID0gTV9nZXRfcmFuZG9tKGdlbik7CgogICAgY29uc3QgaW50IHZlcnRleDEgPSBmcmVlX3ZlcnRpY2VzTltyYW5kb21faW5kZXhfbl07CiAgICBjb25zdCBpbnQgdmVydGV4MiA9IGZyZWVfdmVydGljZXNNW3JhbmRvbV9pbmRleF9tXTsKCiAgICBzb2x1dGlvbi5wdXNoX2JhY2soeyB2ZXJ0ZXgxLCB2ZXJ0ZXgyIH0pOwoKICAgIHZlcnRleF91c2VkW3ZlcnRleDFdKys7CiAgICB2ZXJ0ZXhfdXNlZFt2ZXJ0ZXgyXSsrOwogICAgaWYodmVydGV4X3VzZWRbdmVydGV4MV0gPT0gMikgZnJlZV92ZXJ0aWNlc04uZXJhc2UoZnJlZV92ZXJ0aWNlc04uYmVnaW4oKSArIHJhbmRvbV9pbmRleF9uKTsKICAgIGlmKHZlcnRleF91c2VkW3ZlcnRleDJdID09IDIpIGZyZWVfdmVydGljZXNNLmVyYXNlKGZyZWVfdmVydGljZXNNLmJlZ2luKCkgKyByYW5kb21faW5kZXhfbSk7CiAgfQogIHJldHVybiBzb2x1dGlvbjsKfQoKcGFpcjx2ZWN0b3I8cGFpcjxpbnQsIGludD4+LCB2ZWN0b3I8cGFpcjxpbnQsIGludD4+PiBjaG9vc2VfcGFyZW50cyh2ZWN0b3I8dmVjdG9yPHBhaXI8aW50LCBpbnQ+Pj4gcG9wdWxhdGlvbikgewogIHVuaWZvcm1faW50X2Rpc3RyaWJ1dGlvbjw+IGdldF9yYW5kb20oMCwgcG9wdWxhdGlvbi5zaXplKCkgLSAxKTsKICBjb25zdCBpbnQgcmFuZF9wYXJlbnQxID0gZ2V0X3JhbmRvbShnZW4pOwogIGNvbnN0IGludCByYW5kX3BhcmVudDIgPSBnZXRfcmFuZG9tKGdlbik7CiAgcmV0dXJuIHsgcG9wdWxhdGlvbltyYW5kX3BhcmVudDFdLCBwb3B1bGF0aW9uW3JhbmRfcGFyZW50Ml0gfTsKfQoKdmVjdG9yPHBhaXI8aW50LCBpbnQ+PiBnZXRfZnJlZV9jb25uZWN0aW9ucyh2ZWN0b3I8dmVjdG9yPGludD4+IGluY29tcGxldGVfZ3JhcGgsIGludCBOLCBpbnQgTSkgewoKICB2ZWN0b3I8cGFpcjxpbnQsIGludD4+IGZyZWVfY29ubmVjdGlvbnM7CgogIGZvcihpbnQgaSA9IDAsIHBhciA9IDI7IGkgPCBOOyArK2ksIHBhciArPSAyKSB7CiAgICBmb3IoaW50IGogPSAwLCBpbXBhciA9IDE7IGogPCBNOyArK2osIGltcGFyICs9IDIpIHsKICAgICAgaWYoaW5jb21wbGV0ZV9ncmFwaFtpXVtqXSA9PSBmYWxzZSkgewogICAgICAgIGZyZWVfY29ubmVjdGlvbnMuZW1wbGFjZV9iYWNrKHBhciwgaW1wYXIpOwogICAgICB9CiAgICB9CiAgfQoKICByZXR1cm4gZnJlZV9jb25uZWN0aW9uczsKfQoKcGFpcjx2ZWN0b3I8cGFpcjxpbnQsIGludD4+LCB2ZWN0b3I8cGFpcjxpbnQsIGludD4+PiBjcm9zc292ZXIodmVjdG9yPHZlY3RvcjxwYWlyPGludCwgaW50Pj4+IHBhcmVudHMsIGludCBOLCBpbnQgTSkgewogIC8vLy8gQ2hpbGQgMSA9IEhhbGYoUGFyZW50MSkgKyBIYWxmMihQYXJlbnQyKQogIC8vLy8gQ2hpbGQgMiA9IEhhbGYoUGFyZW50MikgKyBIYWxmMihQYXJlbnQxKQoKICAvLyBwcm9iYWJpbGlkYWRlIGRlIHRyb2NhID0gNTAlOwogIHVuaWZvcm1faW50X2Rpc3RyaWJ1dGlvbjw+IGdldF9yYW5kb20oMCwgMSk7CiAgY29uc3QgaW50IHN3YXBfID0gZ2V0X3JhbmRvbShnZW4pOwogIGlmKHN3YXBfKSB7CiAgICBzd2FwKHBhcmVudHNbMF0sIHBhcmVudHNbMV0pOwogIH0KCiAgdmVjdG9yPHZlY3Rvcjx2ZWN0b3I8aW50Pj4+IGdyYXBoKDIsIHZlY3Rvcjx2ZWN0b3I8aW50Pj4oZ2V0X3Jvd19zaXplKE4pLCB2ZWN0b3I8aW50PihnZXRfY29sX3NpemUoTSksIGZhbHNlKSkpOwogIHZlY3Rvcjx2ZWN0b3I8cGFpcjxpbnQsIGludD4+PiBjb25uZWN0aW9ucygyKTsKICBpbnQgbnVtX29mX2Nvbm5lY3Rpb25zWzJdID0gezB9OwogIGNvbnN0IGludCBIQUxGID0gbWluKE4sIE0pIC8gMjsKCiAgZm9yKGludCBpID0gMDsgaSA8IEhBTEY7ICsraSkgewogICAgZm9yKGludCBwYXJlbnQgPSAwOyBwYXJlbnQgPCAyOyArK3BhcmVudCkgewogICAgICBjb25zdCBhdXRvIFt2ZXJ0ZXgxLCB2ZXJ0ZXgyXSA9IHBhcmVudHNbcGFyZW50XVtpXTsKICAgICAgY29uc3QgaW50IGNoaWxkID0gcGFyZW50OwogICAgICBncmFwaFtjaGlsZF1bdmVydGV4MV1bdmVydGV4Ml0gPSB0cnVlOwogICAgICBjb25uZWN0aW9uc1tjaGlsZF0uZW1wbGFjZV9iYWNrKHZlcnRleDEsIHZlcnRleDIpOwogICAgICArK251bV9vZl9jb25uZWN0aW9uc1tjaGlsZF07CiAgICB9CiAgfQogIGZvcihpbnQgaSA9IEhBTEY7IGkgPCBtaW4oTiwgTSk7ICsraSkgewogICAgZm9yKGludCBwYXJlbnQgPSAwOyBwYXJlbnQgPCAyOyArK3BhcmVudCkgewogICAgICBjb25zdCBhdXRvIFt2ZXJ0ZXgxLCB2ZXJ0ZXgyXSA9IHBhcmVudHNbcGFyZW50XVtpXTsKICAgICAgY29uc3QgaW50IGNoaWxkID0gcGFyZW50OwogICAgICBpZihncmFwaFtjaGlsZF1bdmVydGV4MV1bdmVydGV4Ml0gPT0gZmFsc2UpIHsKICAgICAgICBncmFwaFtjaGlsZF1bdmVydGV4MV1bdmVydGV4Ml0gPSB0cnVlOwogICAgICAgIGNvbm5lY3Rpb25zW2NoaWxkXS5lbXBsYWNlX2JhY2sodmVydGV4MSwgdmVydGV4Mik7CiAgICAgICAgKytudW1fb2ZfY29ubmVjdGlvbnNbY2hpbGRdOwogICAgICB9CiAgICB9CiAgfQogIAogIHZlY3RvcjxwYWlyPGludCwgaW50Pj4gZnJlZV9jb25uZWN0aW9uc1syXTsKICBmcmVlX2Nvbm5lY3Rpb25zWzBdID0gZ2V0X2ZyZWVfY29ubmVjdGlvbnMoZ3JhcGhbMF0sIE4sIE0pOwogIGZyZWVfY29ubmVjdGlvbnNbMV0gPSBnZXRfZnJlZV9jb25uZWN0aW9ucyhncmFwaFsxXSwgTiwgTSk7CgogIGZvcihpbnQgY2hpbGQgPSAwOyBjaGlsZCA8IDI7ICsrY2hpbGQpIHsKICAgIHZlY3RvcjxpbnQ+IHZlcnRleF91c2VkKG1heChnZXRfcm93X3NpemUoTiksIGdldF9jb2xfc2l6ZShNKSkpOwogICAgd2hpbGUobnVtX29mX2Nvbm5lY3Rpb25zW2NoaWxkXSA8IG1pbihOLCBNKSkgewogICAgICB1bmlmb3JtX2ludF9kaXN0cmlidXRpb248PiBnZXRfcmFuZG9tX2luZGV4KDAsIGZyZWVfY29ubmVjdGlvbnNbY2hpbGRdLnNpemUoKS0xKTsKICAgICAgaW50IHJhbmRvbV9pbmRleCwgdmVydGV4MSwgdmVydGV4MjsKICAgICAgYm9vbCB2YWxpZF9lZGdlID0gZmFsc2U7CiAgICAgIHdoaWxlKHZhbGlkX2VkZ2UgPT0gZmFsc2UpIHsKICAgICAgICByYW5kb21faW5kZXggPSBnZXRfcmFuZG9tX2luZGV4KGdlbik7CiAgICAgICAgcGFpcjxpbnQsIGludD4gdmVydGljZXMgPSBmcmVlX2Nvbm5lY3Rpb25zW2NoaWxkXVtyYW5kb21faW5kZXhdOwogICAgICAgIHZlcnRleDEgPSB2ZXJ0aWNlcy5maXJzdCwgdmVydGV4MiA9IHZlcnRpY2VzLnNlY29uZDsKICAgICAgICBpZih2ZXJ0ZXhfdXNlZFt2ZXJ0ZXgxXSA9PSBmYWxzZSAmJiB2ZXJ0ZXhfdXNlZFt2ZXJ0ZXgyXSA9PSBmYWxzZSkgewogICAgICAgICAgY29ubmVjdGlvbnNbY2hpbGRdLmVtcGxhY2VfYmFjayhmcmVlX2Nvbm5lY3Rpb25zW2NoaWxkXVtyYW5kb21faW5kZXhdKTsKICAgICAgICAgIHZhbGlkX2VkZ2UgPSB0cnVlOwogICAgICAgICAgKytudW1fb2ZfY29ubmVjdGlvbnNbY2hpbGRdOwogICAgICAgIH0KICAgICAgICBmcmVlX2Nvbm5lY3Rpb25zW2NoaWxkXS5lcmFzZShmcmVlX2Nvbm5lY3Rpb25zW2NoaWxkXS5iZWdpbigpICsgcmFuZG9tX2luZGV4KTsKICAgICAgfQogICAgfQogIH0KCiAgcmV0dXJuIHBhaXI8dmVjdG9yPHBhaXI8aW50LCBpbnQ+PiwgdmVjdG9yPHBhaXI8aW50LCBpbnQ+Pj4oY29ubmVjdGlvbnNbMF0sIGNvbm5lY3Rpb25zWzFdKTsKfQoKdmVjdG9yPHBhaXI8aW50LCBpbnQ+PiBtdXRhdGUodmVjdG9yPHBhaXI8aW50LCBpbnQ+PiBzb2x1dGlvbiwgaW50IE4sIGludCBNKSB7CiAgdmVjdG9yPHZlY3RvcjxpbnQ+PiBncmFwaChnZXRfcm93X3NpemUoTiksIHZlY3RvcjxpbnQ+KGdldF9jb2xfc2l6ZShNKSwgZmFsc2UpKTsKICBmb3IoYXV0byBbdmVydGV4MSwgdmVydGV4Ml0gOiBzb2x1dGlvbikgewogICAgZ3JhcGhbdmVydGV4MV1bdmVydGV4Ml0gPSB0cnVlOwogIH0KICB2ZWN0b3I8cGFpcjxpbnQsIGludD4+IGZyZWVfZWRnZXMgPSBnZXRfZnJlZV9jb25uZWN0aW9ucyhncmFwaCwgTiwgTSk7CiAgCiAgdW5pZm9ybV9pbnRfZGlzdHJpYnV0aW9uPD4gZ2V0X3JhbmRvbV9pbmRleF9vZl91c2VkX2VkZ2VzKDAsIHNvbHV0aW9uLnNpemUoKS0xKTsKICB1bmlmb3JtX2ludF9kaXN0cmlidXRpb248PiBnZXRfcmFuZG9tX2luZGV4X29mX2ZyZWVfZWRnZXMoMCwgZnJlZV9lZGdlcy5zaXplKCktMSk7CiAgY29uc3QgaW50IHJhbmRvbV9pbmRleF9vZl91c2VkX2VkZ2VzID0gZ2V0X3JhbmRvbV9pbmRleF9vZl91c2VkX2VkZ2VzKGdlbik7CiAgY29uc3QgaW50IHJhbmRvbV9pbmRleF9vZl9mcmVlX2VkZ2VzID0gZ2V0X3JhbmRvbV9pbmRleF9vZl9mcmVlX2VkZ2VzKGdlbik7CiAgc29sdXRpb24uZXJhc2Uoc29sdXRpb24uYmVnaW4oKSArIHJhbmRvbV9pbmRleF9vZl91c2VkX2VkZ2VzKTsKICBzb2x1dGlvbi5lbXBsYWNlX2JhY2soZnJlZV9lZGdlc1tyYW5kb21faW5kZXhfb2ZfZnJlZV9lZGdlc10pOwogIHJldHVybiBzb2x1dGlvbjsKfQo=