DOMANDA C++| Piazzare regine su una schacchiera

Marcus Aseth

Utente Attivo
404
138
OS
Windows 10
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:

BAT

Moderatore
Staff Forum
Utente Èlite
22,923
11,563
CPU
1-Neurone
Dissipatore
Ventaglio
RAM
Scarsa
Net
Segnali di fumo
OS
Windows 10000 BUG
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
 
  • Mi piace
Reazioni: Marcus Aseth

Marcus Aseth

Utente Attivo
404
138
OS
Windows 10
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:

DispatchCode

Moderatore
Staff Forum
Utente Èlite
2,223
1,853
CPU
Intel I9-10900KF 3.75GHz 10x 125W
Dissipatore
Gigabyte Aorus Waterforce X360 ARGB
Scheda Madre
Asus 1200 TUF Z590-Plus Gaming ATX DDR4
HDD
1TB NVMe PCI 3.0 x4, 1TB 7200rpm 64MB SATA3
RAM
DDR4 32GB 3600MHz CL18 ARGB
GPU
Nvidia RTX 3080 10GB DDR6
Audio
Integrata 7.1 HD audio
Monitor
LG 34GN850
PSU
Gigabyte P850PM
Case
Phanteks Enthoo Evolv X ARGB
Periferiche
MSI Vigor GK30, mouse Logitech
Net
FTTH Aruba, 1Gb (effettivi: ~950Mb / ~480Mb)
OS
Windows 10 64bit / OpenSUSE Tumbleweed

Marcus Aseth

Utente Attivo
404
138
OS
Windows 10
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:

DispatchCode

Moderatore
Staff Forum
Utente Èlite
2,223
1,853
CPU
Intel I9-10900KF 3.75GHz 10x 125W
Dissipatore
Gigabyte Aorus Waterforce X360 ARGB
Scheda Madre
Asus 1200 TUF Z590-Plus Gaming ATX DDR4
HDD
1TB NVMe PCI 3.0 x4, 1TB 7200rpm 64MB SATA3
RAM
DDR4 32GB 3600MHz CL18 ARGB
GPU
Nvidia RTX 3080 10GB DDR6
Audio
Integrata 7.1 HD audio
Monitor
LG 34GN850
PSU
Gigabyte P850PM
Case
Phanteks Enthoo Evolv X ARGB
Periferiche
MSI Vigor GK30, mouse Logitech
Net
FTTH Aruba, 1Gb (effettivi: ~950Mb / ~480Mb)
OS
Windows 10 64bit / OpenSUSE Tumbleweed
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.
 
  • Mi piace
Reazioni: Marcus Aseth

Ci sono discussioni simili a riguardo, dai un'occhiata!

Entra

oppure Accedi utilizzando
Discord Ufficiale Entra ora!

Discussioni Simili