八皇后

关键:回溯法
方法一:用二维数组代表棋盘,皇后在的格子为true,其它为false。从第一行开始,放入一个皇后,然后到第二行,检查合法的格子,放入第二个皇后,依次下去,直到某一行没有合法的格子放下皇后,然后撤回上一次放入的皇后,重新寻找合法的格子以放下该皇后。重复上面的步骤。直到皇后全部摆好为止。

代码:

#ifndef QUEENS_H
#define QUEENS_H
#include
using namespace std;

const int maxSize = 32;

class Queens
{
public:
    Queens(int size)
    {
        this->size = size;
        count = 0;
        resultNumber = 0;

        for (int i = 0; i < size; ++i)
            for (int j = 0; j < size; ++j)
            {
                board[i][j] = false;
            }
    }

    bool solved() const
    {
        return size == count;
    }

    bool unguarded(int col) const
    {
        bool ok = true;
        int i;

        for (i = 0; ok && i < count; ++i)
        {
            if (board[i][col] == true)
            {
                ok = !board[i][col];
                return ok;
            }

        }


        for (i = 1; ok && i <= count && i <= col; ++i)
        {
            if (board[count - i][col - i] == true)
            {
                ok = !board[count - i][col - i];
                return ok;
            }

        }

        for (i = 1; ok && i <= count && i < size - col; ++i)
        {
            if (board[count - i][col + i] == true)
            {
                ok = !board[count - i][col + i];
                return ok;
            }

        }

        return ok;
    }

    void insert(int col)
    {
        board[count++][col] = true;
    }

    void remove(int col)
    {
        board[--count][col] = false;
    }

    void print() 
    {
    resultNumber++;
        cout << resultNumber << endl;

        for (int i = 0; i < size; ++i)
            for (int j = 0; j < size; ++j)
            {
                cout << board[i][j];

                if (j == size - 1)
                    cout << endl;
            }

    }

    int getSize() { return size; };

private:
    int size;
    int count;
    long resultNumber;
    bool board[maxSize][maxSize];
};


#endif // !QUEENS_H

void solve(Queens &config)
{
    if (config.solved())
        config.print();
    else
    {
            for (int j = 0; j < config.getSize(); ++j)
            {
                if (config.unguarded(j))
                {
                    config.insert(j);
                    solve(config);
                    config.remove(j);
                }
            }
        }
}


int main()
{
    int numberOfQueens;
    cout << "input the number of queens, no more than 32\n ";
    cin >> numberOfQueens;

    Queens config(numberOfQueens);
    solve(config);

    return 0;
}

分析:方法一中,大量的时间浪费在检查格子的合法性上面,因为该函数存在循环。可以通过改变二维数组的数据,使其存储被控制的次数,如2表示两个皇后控制它,0表示它是可以放皇后的。回溯时,将其值减一。这样改进,可以减小复杂度,但是在插入皇后时,还是需要循环来设置它所控制的格子。还可以改进,完全消去循环。使用原本的定义,找出空闲的列,和斜线。斜线分上斜线与下斜线。每条上斜线上的格子,行加列为固定值,每条下斜线的格子,行减列为固定值。因此不再是检查空闲的格子,而是检查空闲的列和斜线,这可以根据传来的参数(列)立即确定,插入时也只是写入对列和斜线的控制,从而消去循环。

代码:

#ifndef QUEENS2_H
#define QUEENS2_H
#include
using namespace std;

const int maxSize = 32;

class Queens2
{
public:
    Queens2(int size)
    {
        this->size = size;
        count = 0;
        resultNumber = 0;

        for (int i = 0; i < maxSize; ++i) colFree[i] = true;

        for (int i = 0; i < 2 * maxSize - 1; ++i) downFree[i] = true;

        for (int i = 0; i < 2 * maxSize - 1; ++i) upFree[i] = true;
    }

    bool solved() const
    {
        return size == count;
    }

    bool unguarded(int col) const
    {
        return colFree[col] && upFree[count + col] && downFree[count - col + size - 1];
    }

    void insert(int col)
    {
        queenInRow[count] = col;
        colFree[col] = false;
        upFree[count + col] = false;
        downFree[count - col + size - 1] = false;
        ++count;
    }

    void remove(int col)
    {
        --count;
        colFree[col] = true;
        upFree[count + col] = true;
        downFree[count - col + size - 1] = true;
    }

    void print()
    {
        resultNumber++;
        cout << resultNumber << endl;

        for (int i = 0; i < size; ++i)
        for (int j = 0; j < size; ++j)
        {
            if (j == queenInRow[i])
                cout << '1';
            else
                cout << '0';

        if (j == size - 1)
        cout << endl;
        }

    }

    int getSize() { return size; };

private:
    int size;
    int count;
    long resultNumber;
    int queenInRow[maxSize];
    bool colFree[maxSize];
    bool downFree[2 * maxSize - 1];
    bool upFree[2 * maxSize - 1];
};


#endif // !QUEENS_H

void solve(Queens2 &config)
{
    if (config.solved())
        config.print();
    else
    {
            for (int j = 0; j < config.getSize(); ++j)
            {
                if (config.unguarded(j))
                {
                    config.insert(j);
                    solve(config);
                    config.remove(j);
                }
            }
        }
}

int main()
{
    int numberOfQueens;
    cout << "input the number of queens, no more than 32\n ";
    cin >> numberOfQueens;

    Queens2 config(numberOfQueens);
    solve(config);

    return 0;
}

经过改进,程序所需要的步骤已经接近回溯中探查的步骤数。然而皇后问题复杂度比指数还大,这是算法的本质所致。也是该问题的本质使然。

你可能感兴趣的:(数据结构)