Capítulo 25

Números Primos

Em particular, sabendo a quantidade de divisores de cada número, podemos varrer esse vetor vendo quais números são primos (tem 2 divisores).

vector<int> primos_ate_n(int N) {
  vector<int> primos;
  for(int x = 1; x < N; x++) {
    if(qnt_div[x] == 2)
      primos.push_back(x);
  }
  return primos;
}

Crivo de erastótenes

A abordagem acima tem uma complexidade aceitável, e passaria no tempo para a maioria dos problemas. No entanto, existe um algoritmo com uma ideia semelhante, mas que com algumas observações baixa essa complexidade de O(n * log n) para O(n * log( log n)). O log já abaixa muito um número, se aplicamos ele novamente, abaixamos mais ainda, ou seja, isso é quase linear.

A ideia usada é marcar inicialmente todos os números entre 1 e N como possiveis primos. Passando em ordem crescente e quando encontramos um primo marcamos os múltiplos do primo como não primos.

Visualização

Crivo

Implementação

vector<int> primos_ate_n(int N) {
  vector<int> marcacao(N, 1); // 1 = possivel primo, 0 = com certeza não primo
  vector<int> primos;
  for(int x = 2; x < N; x++) if(marcacao[x] == 1) {
    primos.push_back(x);
    for(int m = x+x; m < N; m += x) {
      marcacao[m] = 0; // aqui descobrimos que m não é primo
    }
  }
  return primos;
}