DOMANDA C++| Piazzare regine su una schacchiera

Pubblicità

Marcus Aseth

Utente Attivo
Messaggi
408
Reazioni
138
Punteggio
60
Cercavo di risolvere la sfida proposta a metà di questa pagina.
In sostanza dato un singolo input N, bisogna creare una scacchiera NxN e scoprire se è possibile piazzarci sopra N Regine in maniera tale che nessuna di loro minacci un'altra.
Al solito temo di aver complicato la mia soluzione piu del dovuto, tuttavia dà la risposta corretta e passa tutti i testcase, solo che al di sopra di un input quale 7, comincia a diventare troppo lento, temo che la complessità del mio algoritmo sia O(n^n).
Mi domandavo, c'è un modo migliore per completare la sfida che permetta anche di gestire input piu grandi di 7 in tempi ragionevoli? :S


C++:
#include <iostream>
#include <vector>
using namespace std;

struct pos {
    int x;
    int y;
};

class Board {
public:
    Board(int n) :board(n, vector<int>(n, 0)), gridSize{ n } {}
    Board& operator=(const Board& rhs);
    //methods
    void addQueen(int x, int y);
    bool isSolved() { return queens.size() == gridSize; }
    void printQueens();
    //variables
    vector<vector<int>> board;
    vector<pos> queens;
    int gridSize;
private:
    void updateOccupied();
};

Board placeQueens(Board);

int main()
{
    int N{};
    cin >> N;

    Board state(N);
    state = placeQueens(state);

    if (state.queens.size() == N)
    {
        cout << "YES" << endl;
        state.printQueens();
    }
    else
    {
        cout << "NO" << endl;
    }

    return 0;
}

Board placeQueens(Board current)
{
    // starts the outer for loop from the row of the last queen placed onward
    int y = (current.queens.empty())? 0 : current.queens.back().y;

    Board temp(current.gridSize);
    for (int i = y; i < current.board.size(); i++)
    {
        for (int j = 0; j < current.board[0].size(); j++)
        {
            if (current.board[i][j] == 0)
            {
                temp = current;
                temp.addQueen(j, i);
               
                //base case 1 the first time an answer is found
                if (temp.isSolved()) {return temp;}
               
                //recursion
                temp = placeQueens(temp);
               
                //base case 2 to propagate up the correct answer
                if (temp.isSolved()) { return temp; }
            }
        }
    }
    return current;
}

void Board::addQueen(int x, int y)
{
    queens.push_back(pos{ x, y });
    this->updateOccupied();
}

void Board::updateOccupied()
{
    pos& p = queens.back();
    //horizontal
    board[p.y] = vector<int>(gridSize, 1);

    //vertical
    for (int i = 0; i < gridSize; i++) { board[i][p.x] = 1; }

    //diagonal
    bool toggle = true;
    int xSign = -1, ySign = -1;
    for (int i = 0; i < 4; i++)
    {
        int x = p.x;
        int y = p.y;
        while (
            x + xSign >= 0 && x + xSign < gridSize &&
            y + ySign >= 0 && y + ySign < gridSize
            )
        {
            x += xSign;
            y += ySign;
            board[y][x] = 1;
        }
        xSign = toggle ? xSign * -1 : xSign;
        ySign = toggle ? ySign : ySign * -1;
        toggle = !toggle;
    }
}

void Board::printQueens()
{
    Board temp(gridSize);
    for (auto& q : queens) {
        temp.board[q.y][q.x] = 1;
    }
    for (int i = 0; i < temp.gridSize; i++)
    {
        for (int j = 0; j < temp.gridSize; j++)
        {
            cout << temp.board[i][j];
            if (j != temp.gridSize - 1) {
                cout << " ";
            }
        }
        cout << endl;
    }
}

Board& Board::operator=(const Board& rhs)
{
    board = rhs.board;
    queens = rhs.queens;
    gridSize = rhs.gridSize;
    return *this;
}
 
Ultima modifica:
si tratta della variante generica di un noto problema chiamato "problema delle 8 regine";
non ho più gli appunti ed è troppo lontano nel tempo per me per aiutarti, ma ricordo che si risolve con la tecnica del backtracking.
Ti conviene fare una ricerca con Google e vedrai che trovi la soluzione (almeno di quello con n=8), è un problema classico degli esami di tecniche di programmazione
 
Ho visto l'animazione .gif del backtracking, e mi pare proprio sia la stessa cosa che sta facendo il mio algoritmo.
Il codice che ho trovato però è la metà del mio, come sempre xD sarà perchè ogni volta mi incarto nel costruire classi :/
 
Ultima modifica:
Cosa invece differente, ma con un algoritmo che potrebbe magari interessarti, è questo: un maze solver in Java, sempre risalente a qualche anno fa: https://pastebin.com/6qgzZbny

Dovrò ricordarmi di hostarli su github, alcuni sono piuttosto carini...


Edit: aggiunte le immagini

Funziona? :S
Stavo dando un'occhiata e sono confuso alla linea:

Codice:
 boolean analizzaStruttura(int x, int y) {
    if(maze[x][y] == 'E') return true;
    if(maze[x][y] == '*') return false;
    if(maze[x][y] == '+') return false;
    maze[x][y] = '+';
 
    if(analizzaStruttura(x, y-1)) return true;

cioè non so se funziona diversamente da C++, ma non vedo i "boundary checks" per gli index all'array, analizzaStruttura(x, y-1) dopo alcune iterazioni non comincia ad accedere index inferiori a 0?! (nel caso non incontra uno di quei 3 simboli)

La funzione è chiamata con input (0, 5) e da quel che vedo a 0,5 ci sta 'S', percui i primi 3 check danno false, la S diventa '+' e poi procede a controllare 0,4 che in questo caso è un asterisco e và d'accordo col fatto che hai piazzato la Start in alto, ma se avevi un maze con 'S' nel muro a sinistra, non dovrebbe crashare subito in seguito al tentativo di accedere 0,-1?

nota a parte: personalmente preferisco maze[y][x] perchè le prime parentesi quadre di fatto rapresentano il movimento su è giu tra le varie row dell'array 2D, che quindi corrisponde di piu a quello che noi intendiamo per Y, personalmente mi aiuta a ragionarci :S
 
Ultima modifica:
Scusa il ritardo nella risposta.
Funzionare funziona. Il codice doveva rispettare solo alcune regole, ed era scritto proprio sull'assunto che ci sarebbero stati un determinato tipo di dati. Ad ogni modo si, è corretto verificare che la posizione esista.
 
Pubblicità
Pubblicità
Indietro
Top