Todos os desafios
Médio 0 resolvidos 0% de aceitação

Uma geração de um algoritmo genético

Gere a próxima geração de strings de bits com seleção por torneio, cruzamento de um ponto e mutação.

O que você vai aprender

  • Selecionar pais por torneio
  • Combinar soluções com cruzamento
  • Adicionar variação com mutação

Problema

Ver original (inglês)

Um algoritmo genético melhora uma população de soluções candidatas como a evolução faz: seleciona pais aptos, combina-os e adiciona mutações aleatórias. Aqui os candidatos são strings de bits e a aptidão é o número de 1s (o problema OneMax).

Para que possa ser testado, cada escolha aleatória é fornecida. Com N strings (N par), construa N filhos em pares. Para o par k = 0, 1, …, N/2 - 1:

  1. Seleção: parent1 vence o torneio tournaments[2k] e parent2 vence tournaments[2k + 1]. Um torneio [i, j] é vencido por aquela entre population[i] e population[j] que tiver mais 1s; em caso de empate, population[i] vence.
  2. Cruzamento em c = crossover_points[k]: filho 2k = parent1[0:c] + parent2[c:] e filho 2k + 1 = parent2[0:c] + parent1[c:].

Depois aplique cada mutação [child, position] em ordem, invertendo aquele bit daquele filho.

Implemente ga_generation(population, tournaments, crossover_points, mutations).

Entrada

population: N strings de bits com o mesmo comprimento L.

tournaments: N pares de índices da população.

crossover_points: N/2 pontos de corte, cada um entre 1 e L - 1.

mutations: Pares [child, position] (pode ser vazio).

Saída

Retorne os N filhos em ordem.

Restrições

2 ≤ N ≤ 200 (N par), 2 ≤ L ≤ 64

0 ≤ número de mutações ≤ 1.000

Exemplos

Exemplo 1
Entrada:
mutations = [
    [0, 0]
]
population = ["0000", "1111", "1100", "0011"]
tournaments = [
    [0, 1],
    [2, 3],
    [1, 2],
    [0, 3]
]
crossover_points = [2, 1]

Saída esperada:
expected = ["0100", "1111", "1011", "0111"]
Entrada:
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};

Saída esperada:
std::vector<std::string> expected = {"0100", "1111", "1011", "0111"};
Entrada:
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};

Saída esperada:
string[] expected = new string[] {"0100", "1111", "1011", "0111"};

Explicação

Par 0: "1111" vence "0000", e "1100" empata com "0011", então a primeira vence. Cortar após 2 bits dá "1100" e "1111". Par 1: pais "1111" e "0011", corte após 1 bit: "1011" e "0111". Por fim, o filho 0 tem o bit 0 invertido: "0100".

Exemplo 2
Entrada:
mutations = []
population = ["10", "01"]
tournaments = [
    [0, 1],
    [1, 0]
]
crossover_points = [1]

Saída esperada:
expected = ["11", "00"]
Entrada:
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};

Saída esperada:
std::vector<std::string> expected = {"11", "00"};
Entrada:
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};

Saída esperada:
string[] expected = new string[] {"11", "00"};

Explicação

As duas strings têm um único 1, então cada torneio é vencido pelo primeiro índice: parent1 = "10" e parent2 = "01". Cortar após 1 bit dá "11" e "00".

Referências

Este desafio foi adaptado para o CodeUtility. Siga o enunciado e as restrições acima.

Aprenda com outros

Soluções da comunidade

Ainda não há soluções publicadas. Resolva este desafio para compartilhar a primeira.