显示n-queen问题的多个可能性答案

时间:2013-12-20 02:48:27

标签: c++ console console-application

根据用户输入的电路板尺寸编号,我有一些用于在控制台中显示n-queens问题的代码。

以下是代码:

#include <windows.h>
#include <iostream>
#include <string>

using namespace std;

class point
{
public:
    int x, y;
    point() { x = y = 0; }
    void set( int a, int b ) { x = a; y = b; }
};

class nQueens
{
public:
    void solve( int c )
    {
        _count = c;
        int len = (c + 1) * (c + 1);
        _queens = new bool[len]; memset( _queens, 0, len );
        _cl = new bool[c]; memset( _cl, 0, c );
        _ln = new bool[c]; memset( _ln, 0, c );
        point pt; pt.set( rand() % c, rand() % c );
        putQueens( pt, c );
        displayBoard();
        delete [] _queens; delete [] _ln; delete [] _cl;
    }

private:
    void displayBoard()
    {
        system( "cls" );
        const string t = "+---+", q = "| Q |", s = "|   |";
        COORD c = { 0, 0 };
        HANDLE h = GetStdHandle( STD_OUTPUT_HANDLE );
        for (int y = 0, cy = 0; y < _count; ++y)
        {
            int yy = y * _count;
            for ( int x = 0; x < _count; x++ )
            {
                SetConsoleCursorPosition( h, c ); cout << t;
                c.Y++; SetConsoleCursorPosition( h, c );
                if (_queens[x + yy]) cout << q; else cout << s;
                c.Y++; SetConsoleCursorPosition( h, c );
                cout << t; c.Y = cy; c.X += 4;
            }
            cy += 2; c.X = 0; c.Y = cy;
        }
    }

    bool checkD( int x, int y, int a, int b )
    {
        if ( x < 0 || y < 0 || x >= _count || y >= _count ) return true;
        if ( _queens[x + y * _count] ) return false;
        if ( checkD( x + a, y + b, a, b ) ) return true;
        return false;
    }

    bool check( int x, int y )
    {
        if ( _ln[y] || _cl[x] )        return false;
        if ( !checkD( x, y, -1, -1 ) ) return false;
        if ( !checkD( x, y,  1, -1 ) ) return false;
        if ( !checkD( x, y, -1,  1 ) ) return false;
        if ( !checkD( x, y,  1,  1 ) ) return false;
        return true;
    }

    bool putQueens( point pt, int cnt )
    {
        int it = _count;
        while (it)
        {
            if ( !cnt ) return true;
            if ( check( pt.x, pt.y ) )
            {
                _queens[pt.x + pt.y * _count] = _cl[pt.x] = _ln[pt.y] = true;
                point tmp = pt;
                if ( ++tmp.x >= _count ) tmp.x = 0;
                if ( ++tmp.y >= _count ) tmp.y = 0;
                if ( putQueens( tmp, cnt - 1 ) ) return true;
                _queens[pt.x + pt.y * _count] = _cl[pt.x] = _ln[pt.y] = false;
            }
            if ( ++pt.x >= _count ) pt.x = 0;
            it--;
        }
        return false;
    }

    int          _count;
    bool*        _queens, *_ln, *_cl;
};

int main( int argc, char* argv[] )
{
    nQueens n; int nq;
    while( true )
    {
        system( "cls" );
        cout << "Enter board size bigger than 3 (0 - 3 to QUIT): "; cin >> nq;
        if ( nq < 4 ) return 0;
        n.solve( nq ); cout << endl << endl;
        system( "pause" );
    }
    return  0;
}

控制台显示是这样的。假设我输入4: first display input

然后结果:

result display

我想知道我是否可以在应用程序中添加另一种可能性,因为4x4板可以有2个解决方案。一些帮助将不胜感激 - 谢谢!

ps:代码不是由我完全创建的,我完全忘记了我是如何获得第一个代码算法的,我对此代码不予理睬:)

4 个答案:

答案 0 :(得分:1)

我认为你的算法只生成一个答案。 你应该以某种方式组织它,当下一个答案可以从电路板的存储状态计算出来。皇后。

NQueens q;
while(q.next()) // search next solution
{
    q.clearScreen(); // OR clrscr();
    q.displayBoard();
    char c = getch();
    if(c != ' ') break; // Interrupt loop when user press key, but not space
    // When user press space he will see next answer
}

答案 1 :(得分:1)

#include <iostream>

using namespace std;

const int N = 5;
int position[N];

// Check if a position is safe
bool isSafe(int queen_number, int row_position)
{
        // Check each queen before this one
        for(int i=0; i<queen_number; i++)
        {
                // Get another queen's row_position
                int other_row_pos = position[i];

                // Now check if they're in the same row or diagonals
                if(other_row_pos == row_position || // Same row
                        other_row_pos == row_position - (queen_number-i) || // Same diagonal
                        other_row_pos == row_position + (queen_number-i))   // Same diagonal
                        return false;
        }
        return true;
}


// Recursively generate a tuple like [0 0 0 0], then [0 0 0 1] then etc...
void solve(int k)
{
        if(k == N) // We placed N-1 queens (0 included), problem solved!
        {
                // Solution found!
                cout << "Solution: ";
                for(int i=0; i<N; i++)
                        cout << position[i] << " ";
                cout << endl;
        }
        else
        {
                for(int i=0; i<N; i++) // Generate ALL combinations
                {
                        // Before putting a queen (the k-th queen) into a row, test it for safeness
                        if(isSafe(k,i))
                        {
                                position[k] = i;
                                // Place another queen
                                solve(k+1);
                        }
                }
        }
}

int main()
{
        solve(0);

        return 0;
}

希望这会有所帮助:)

答案 2 :(得分:0)

而不是return true

if( !cnt ) 
    return true;

让它显示结果(即调用displayBoard),然后返回false。这将导致求解器继续运行,直到它耗尽所有可能性。

您需要移除displayBoardsolve的来电,并且您可能需要调整您正在调用的地点system("CLS"),以便获得您喜欢的整体结果。

答案 3 :(得分:0)

if( !cnt ) 
return true;

让它显示结果(即调用displayBoard),然后显示return false。这将导致求解器继续运行,直到它耗尽所有可能性。

您需要在解决时删除对displayBoard的调用,并且您可能需要调整您正在调用系统的位置(“CLS”)以获得您喜欢的整体结果