Informatica 2 Liceo Scientifico Scienze Applicate/Backtracking

Indice del libro

Il problema delle 8 Regine

modifica

Ilproblema delle otto regine è un problema che consiste nel trovare come posizionare otto regine su una scacchiera 8x8 in modo che nessuna regina possa catturarne un'altra. Quindi se posiziono una regina in una casella (r,c) non posso posizionarne un'altra sulla stessa colonna (c) o stessa riga (r) o sulle due diagonali associate (r+c=k) e (r-c=k), questo perché la regina può mangiare in orizzontale, in verticale e lungo le due diagonali. Il problema rientra nella categoria del backtracking e in questa soluzione usa la ricorsione.

 

Se provate a risolvere il problema probabilmente usate come struttura dati per rappresentare la schacchiera una matrice 8*8, ma c'e' una soluzione più efficiente che impiega 4 vettori: uno per dire se la riga da 0 a 7 è occupata o no da una regina uno per dire se la colonna da 0 a 7 è occupata o no da una regina uno per dire se la diagonale (in avanti) da 0 a 14 è occupata o no da una regina uno per dire se la diagonale (in indietro) da 0 a 14 è occupata o no da una regina

si ricorda che la diagonale k in avanti è costituita dalle sole celle la cui sooma degli indici è uguale a k, ad esempio la diagonale 3 ha come celle (0,3) (1,2) (2,1) e (3.0). In modo analogo per le diagonali all'indietro che sono costituite dalle sole celle di indici i,j con i-j=k con k che individua il numero della diagonale, essendo i-j una espressione che può assumere nel caso della scacchiera valori da -7 a +7 e avendo intenzione di usare k=i-j come indice del vettore (che nel c possono essere solo positivi si decide per individuare l'indice del vettore l'espressione k=i-j+7, cosi da avere sempre indici non negativi.

Nella soluzione proposta i vettori (di bool, true=libera,false =occupata da una regina) sono dichiarate come variabili globali, evitando di doverle passare come parametri alla funzione ricorsiva "regina".

Per la verità il vettore delle righe non viene dichiarato, perché senza perdità di generalità (non si perdono soluzioni) l'r-sima regina sarà posizionata nella riga r (8 regine 8 righe, una per riga), la funzione regina(r) utilizza solo posizionamenti della regina sulla riga r, quindi la funzione regina(r) andrà ad analizzare il posizionamento della regina r-esima al variare della colonna da 0 a 7. Naturalmente riesco a posizionare una regina riga r, colonna c, solo se col[c], diagavanti[r+c] e diagindetro[r-c+7] sono tutte libere. se lo sono, le occupo e lancio la funzione ricorsiva regina(r+1) che si preoccupa di sistemare un'ulteriore regina (sulla riga successiva). Quando la funzione ricorsiva regina(r+1) termina togliamo la regina riga r colonna c da col[c], diagavanti[r+c] e diagonaleindietro[r-c+7] perché sulla stessa riga vogliamo provare a sistemare la regina anche sulle colonne successive.

la soluzione (posiziono 8 regine) la registro nel vettore sol, in cui l'indice della cella è il numero della riga dove ho posizionato la regina e il valore della cella con quell'indice rappresenta la colonna dove ho posizionato la regina.

la condizione di terminazione della funzione ricorsiva avviene quando si tenta di posizionare la nona regina regina(8), infatti la numerazione delle regine parte da 0 a 7. In questo caso prima di terminare stampa la soluzione trovata (i posizionamenti delle regine da 0 a 7)

Versione animata della soluzione ricorsiva

modifica

 

Questa animazione usa il backtracking per risolvere il problema. Una regina è posizionata in una colonna che non genera conflitto. Se la colonna non viene trovata il programma ritorna all'ultimo stato positivo e viene provata una differente colonna.

Programma in C soluzione ricorsiva

modifica
#include <iostream>
using namespace std;

/* run this program using the console pauser or add your own getch, system("pause") or input loop */


bool col[8]={ true,true,true,true,true,true,true,true };
bool d1[15]={ true,true,true,true,true,true,true,true,true,true,true,true,true,true,true};
bool d2[15]={ true,true,true,true,true,true,true,true,true,true,true,true,true,true,true};
int sol[8];//indice =riga regina, valore della cella corrispondente a quel indice = col reg


void regina(int r)
{ int i,c;
  if(r==8)
   { for(i=0;i<8;i++) 
       cout<<"("<<i<<","<<sol[i]<<")";
     cout<<endl;
   }
  else
   for(c=0;c<8;c++)
     if( col[c] && d1[r+c] && d2[r-c+7])
        { col[c]=false;
          d1[r+c]=false;
          d2[r-c+7]=false;
          sol[r]=c;
          regina(r+1);
          col[c]=true;
          d1[r+c]=true;
          d2[r-c+7]=true;
     	}    
}

int main(int argc, char** argv) 
{  cout<<"le soluzioni sono"<<endl;
   regina(0);
	return 0;
}