LinhaCodigo
001# Prof. Leo^nidas - http://www.matematica.br http://line.ime.usp.br
002# MAC0122 - 2025/08/19
003#
004# Problema das N rainhas
005# Aula 05: problemas das N rainhas (implementa 1: menos eficiente)
006
007from __future__ import print_function
008
009import sys; # Para passar parametro via linha de comando: python problema_n_rainhas.py 5
010
011def imprima_solucao (tabuleiro) :
012  for i in range(N):
013    for j in range(N):
014      print(tabuleiro[i][j],end=' ')
015    print()
016
017# Diagonal principal
018# i : -(n-1), -(n-2), ..., -1, 0, 1, 2, ... (n-1)
019# dp(i): 0, 1, (n-2), (n-1), n, n+1 ... 2n-1 => dp(i) = i+(n-1)
020# i : -3, -2, -1, 0, 1, 2, 3
021# l(i) : 0, 1, 2, 3, 4, 5, 6 => dp(i) = i+3
022
023# Diagonal secundaria
024# ds(i): 0, 1, (n-2), (n-1), n, n+1 ... 2n-1 => ds(i) = i
025
026
027# Verifica se a posicao [lin][col] nao sofre ataque
028def posicaoSegura (tabuleiro, lin, col, vlinha, vcoluna, vdiagp, vdiags) :
029  global N;
030  if (vlinha[lin]==1) : return False;
031  if (vcoluna[col]==1) : return False;
032  if (vdiagp[lin-col+N-1]==1) : return False
033  if (vdiags[lin+col]==1) : return False;
034  vlinha[lin] = 1; # agora linha ocupada
035  vcoluna[col] = 1; # agora coluna ocupada
036  vdiagp[lin-col+N-1] = 1; # agora diagonal principal ocupada: -(n-1), -(n-2), ...0, 1, 2, ... (n-1) <-> 0, 1, ..., n, n+1, n+2, ... 2n-1
037  vdiags[lin+col] = 1; # agora diagonal secundaria ocupada
038  return True; # seguro
039
040def tenta_recursivamente (N, tabuleiro, col, vlinha, vcoluna, vdiagp, vdiags) :
041  # Testa final de posicionamento: col==N => posicionadas N rainhas! Sucesso!
042  if (col >= N) : return True
043  # Considere esta coluna e tente posicionar a rainha na linha i (i de 0 ate' N-1)
044  for lin in range(N):
045    if (posicaoSegura(tabuleiro, lin, col, vlinha, vcoluna, vdiagp, vdiags)) :
046      tabuleiro[lin][col] = 1; # posicione rainha col na linha lin
047      # Agora tente posicioar a rainha col+1
048      if (tenta_recursivamente(N, tabuleiro, col+1, vlinha, vcoluna, vdiagp, vdiags)) :
049         return True; # Teve sucesso com esta posical (posicionou todas)
050      # Se houve erro, desfaca a marcacao para tentar em nova linha
051      tabuleiro[lin][col] = 0; # libere posical do tabuleiro
052      vlinha[lin] = 0; # desocupa linha
053      vcoluna[col] = 0; # desocupa coluna
054      vdiagp[lin-col+N-1] = 0; # desocupa diagonal principal
055      vdiags[lin+col] = 0; # desocupa diagonal secundaria
056  # Se chegou neste ponto, entao nao foi possivel posiciona rainha col, desista...
057  return False;
058
059# Tentativa e erro para o problema das N rainhas
060def n_rainhas (N) :
061  # Solucao menos eficiente
062  tabuleiro = [];
063  for i in range(N) :
064    linhaA = []
065    for j in range(N) :
066      linhaA.append(0);
067    tabuleiro.append(linhaA);
068
069  if (tenta_recursivamente(N, tabuleiro, 0, vlinha, vcoluna, vdiagp, vdiags) == False) :
070    print ("Solution does not exist");
071    return False;
072
073  imprima_solucao(tabuleiro);
074  return True
075
076# Testando o truque da bijecao para a diagonal principal
077def testa_diagonal_p (n) :
078  print("2*N-2 = %d " % (2*n-2));
079  # dp(i) : 0, 1, 2, 3, 4, 5, 6 => dp(i) = i+3
080  for i in range(n) :
081    for j in range(n) : print("%d " % (i-j + n-1), end="");
082    print();
083
084# testa_diagonal_p(N);
085
086# Tenta com N rainhas
087N = int(sys.argv[1]); # pega primeiro argumento (deve ser inteiro)
088
089print("Tenta posicionar %d rainhas em um tabuleiro %d x %d" % (N, N, N));
090
091# Estruturas para algoritmo mais eficiente:
092vlinha = N*[0]; # linha[i] =1 <=> existe rainha na linha i
093vcoluna = N*[0]; # coluna[i]=1 <=> existe rainha na coluna i
094vdiagp = 2*N*[0]; # diagp[i] =1 <=> existe rainha na diagonal princial i (i=-(n-1), -(n-2), ..., 0, 1, 2, ... (n-1))
095vdiags = 2*N*[0]; # diags[i] =1 <=> existe rainha na diagonal secundaria i (i=-0, 1, 2, ... 2*(n-1))
096
097n_rainhas(N);
098
099