Problème
Un algorithme génétique améliore une population de solutions candidates comme le fait l'évolution : sélectionner des parents performants, les combiner et ajouter des mutations aléatoires. Ici, les candidats sont des chaînes de bits et la fitness est le nombre de 1 (le problème OneMax).
Pour rendre le tout testable, chaque choix aléatoire est fourni. Avec N chaînes (N pair), construisez N enfants par paires. Pour la paire k = 0, 1, …, N/2 - 1 :
- Sélection : parent1 remporte le tournoi
tournaments[2k]et parent2 remportetournaments[2k + 1]. Un tournoi[i, j]est remporté par celle depopulation[i]etpopulation[j]qui a le plus de 1 ; en cas d'égalité,population[i]gagne. - Croisement en c =
crossover_points[k]: enfant 2k = parent1[0:c] + parent2[c:] et enfant 2k + 1 = parent2[0:c] + parent1[c:].
Appliquez ensuite chaque mutation [child, position] dans l'ordre en inversant ce bit de cet enfant.
Implémentez ga_generation(population, tournaments, crossover_points, mutations).
Entrée
population : N chaînes de bits de même longueur L.
tournaments : N paires d'indices de la population.
crossover_points : N/2 points de coupe, chacun entre 1 et L - 1.
mutations : Des paires [child, position] (peut être vide).
Sortie
Renvoyez les N enfants dans l'ordre.
Contraintes
2 ≤ N ≤ 200 (N pair), 2 ≤ L ≤ 64
0 ≤ nombre de mutations ≤ 1 000
Exemples
Entrée :
mutations = [
[0, 0]
]
population = ["0000", "1111", "1100", "0011"]
tournaments = [
[0, 1],
[2, 3],
[1, 2],
[0, 3]
]
crossover_points = [2, 1]
Sortie attendue :
expected = ["0100", "1111", "1011", "0111"]
Entrée :
std::vector<std::vector<long long>> mutations = {
{0, 0}
};
std::vector<std::string> population = {"0000", "1111", "1100", "0011"};
std::vector<std::vector<long long>> tournaments = {
{0, 1},
{2, 3},
{1, 2},
{0, 3}
};
std::vector<long long> crossover_points = {2, 1};
Sortie attendue :
std::vector<std::string> expected = {"0100", "1111", "1011", "0111"};
Entrée :
long[][] mutations = new long[][] {
new long[] {0, 0}
};
string[] population = new string[] {"0000", "1111", "1100", "0011"};
long[][] tournaments = new long[][] {
new long[] {0, 1},
new long[] {2, 3},
new long[] {1, 2},
new long[] {0, 3}
};
long[] crossover_points = new long[] {2, 1};
Sortie attendue :
string[] expected = new string[] {"0100", "1111", "1011", "0111"};
Explication
Paire 0 : "1111" bat "0000", et "1100" fait égalité avec "0011", donc la première gagne. Couper après 2 bits donne "1100" et "1111". Paire 1 : parents "1111" et "0011", coupe après 1 bit : "1011" et "0111". Enfin, le bit 0 de l'enfant 0 est inversé : "0100".
Entrée :
mutations = []
population = ["10", "01"]
tournaments = [
[0, 1],
[1, 0]
]
crossover_points = [1]
Sortie attendue :
expected = ["11", "00"]
Entrée :
std::vector<std::vector<long long>> mutations = {};
std::vector<std::string> population = {"10", "01"};
std::vector<std::vector<long long>> tournaments = {
{0, 1},
{1, 0}
};
std::vector<long long> crossover_points = {1};
Sortie attendue :
std::vector<std::string> expected = {"11", "00"};
Entrée :
long[][] mutations = new long[][] {};
string[] population = new string[] {"10", "01"};
long[][] tournaments = new long[][] {
new long[] {0, 1},
new long[] {1, 0}
};
long[] crossover_points = new long[] {1};
Sortie attendue :
string[] expected = new string[] {"11", "00"};
Explication
Les deux chaînes ont un seul 1, donc chaque tournoi est remporté par son premier indice : parent1 = "10" et parent2 = "01". Couper après 1 bit donne "11" et "00".
Comment l'aborder
Essayez d'abord seul, puis ouvrez les indices un par un.
Indice 1
Construisez les enfants par paires en choisissant d’abord deux parents dans chaque tournoi, puis en combinant leurs chaînes binaires à un point de coupure.
Indice 2
La sélection dépend uniquement de la fitness, les égalités favorisant toujours le premier concurrent dans la paire de tournoi.
Indice 3
Appliquez les mutations après avoir créé tous les enfants, et assurez-vous que chaque modification cible la chaîne de l’enfant courant.
Complexité attendue
temps O(N * L + M), espace supplémentaire O(N * L)
Références
Ce défi a été adapté pour CodeUtility. Suivez l'énoncé et les contraintes ci-dessus.