Skip to content

Apresentação de Problemas relacionados

Um dos problemas discutidos nesse tópico é o famoso n-Queen, que consiste em posicionar N rainhas em um tabuleiro de xadrez com tamanho NxN, o algoritmo abaixo utiliza da técnina backtracking, com algumas otimizações específicas, para contar a quantidade de maneiras distintas de resolver esse problema.

#include <bits/stdc++.h>

using namespace std;

int isValidSolution(int x, vector<int> &diagonal_principal,
            vector<int> &diagonal_secundaria,
            vector<int> &tabuleiro){

  int ret = 1;

  // Como já foi garantido que as rainhas estão em linhas
  //e colunas diferentes resta apenas validar as diagonais
  for(int i=0;i<x;++i){
    ret &= (diagonal_secundaria[i + tabuleiro[i]] == 1 &&
    diagonal_principal[i + (x - 1) - tabuleiro[i]] == 1);
  }

  // Caso não haja mais de uma rainha em nenhuma das diagonais
  // os posicionamentos estão validos e o retorno será 1, caso contrário 0.
  return ret;
}


int nQueen(int n, vector<int> &diagonal_principal,
            vector<int> &diagonal_secundaria,
            vector<int> &tabuleiro,
            list<int> &posicoes_disponiveis){

  if(n == 0){ // quando essa condição é satisfeita significa que todas
  //  as N rainhas foram posicionadas de alguma forma

    // Checa se a solução obtida é valida
    return isValidSolution((int)tabuleiro.size(),
    diagonal_principal, diagonal_secundaria, tabuleiro);

  }

  int ans = 0;

  for(int i=0;i<n;++i){

    int k = tabuleiro.size();

    // Posiciona a rainha em uma das colunas disponíveis
    tabuleiro[n - 1] = posicoes_disponiveis.back();

    // Retira essa posição da lista para que as próximas
    // não sejam posicionadas na mesma coluna
    posicoes_disponiveis.pop_back();

    // Aumenta a quantidade de rainhas nas diagonais
    ++diagonal_principal[(n - 1) + (k - 1) - tabuleiro[n - 1]];
    ++diagonal_secundaria[(n - 1) + tabuleiro[n - 1]];

    // Tenta posicionar as n-1 restantes
    ans += nQueen(n-1, diagonal_principal,
                  diagonal_secundaria,
                  tabuleiro,
                  posicoes_disponiveis);

    // Coloca a posição que foi adicionada de volta no começo da lista,
    // para que ela esteja disponível mas não seja repetida pela rainha atual
    posicoes_disponiveis.push_front(tabuleiro[n - 1]);

    // Remove a contagem de rainhas nessas diagonais
    --diagonal_principal[(n - 1) + (k - 1) - tabuleiro[n - 1]];
    --diagonal_secundaria[(n - 1) + tabuleiro[n - 1]];
  }

  return ans;

}

int main() {

  // Declaração e leitura do tamanho do tabuleiro e,
  // logo, quantidade de rainhas
  int N;
  cin >> N;

  // Para verificar quantas rainhas estão posicionadas nas diagonais
  // principais e secundária do tabuleiro
  vector<int> diagonal_principal(2*N, 0), diagonal_secundaria(2*N, 0);

  // Como as rainhas não podem se atacar, já a posicionaremos em linhas e
  // colunas distintas, isso será representado no vector tabuleiro
  // da seguinte forma: tabuleiro[i] = x, onde i = linha em que a rainha está
  // e x = coluna em que a rainha está
  vector<int> tabuleiro(N);
  list<int> posicoes_disponiveis;
  for(int i=0;i<N;++i){
    posicoes_disponiveis.push_back(i);
  }

  cout << nQueen(N, diagonal_principal,
                  diagonal_secundaria,
                  tabuleiro,
                  posicoes_disponiveis)
                  << endl;

  return 0;
}