八皇后问题





判断一个位置上能否放皇后,只需在三个方向上进行判断(下、右下、左下)。

关键数据结构定义:

 int m_chessboard[N][N]; //定义棋盘
enum{ N = SIZE + 2};    //10 * 10 的棋盘
0表示位置为空,1表示皇后,2表示边界

位置:

    struct Pos : public Object
    {
        Pos(int px=0, int py=0) : x(px),y(py) { }
        int x;
        int y;
    };

方向定义:

下:(0, -1)

左下:(-1, -1)

右下:(1, -1)

        //初始化三个方向的方向数据
        m_direction[0].x = -1;
        m_direction[0].y = -1;

        m_direction[1].x = 0;
        m_direction[1].y = -1;

        m_direction[2].x = 1;
        m_direction[2].y = -1;

算法思路:


先定义一个类模板,用来扩展成N皇后问题:

template <int SIZE>
class QueueSolution : public Object
{
protected:
    enum{ N = SIZE + 2}; //设置边界

    struct Pos : public Object
    {
        Pos(int px=0, int py=0) : x(px),y(py) { }
        int x;
        int y;
    };

    int m_chessboard[N][N]; //定义棋盘
    Pos m_direction[3]; //检查三个方向是否有皇后
    LinkList<Pos> m_solution; //存储解决方案 链表
    int m_count; //解决方法数量

    void init()
    {
        m_count = 0;

        for(int i=0; i<N; i += (N-1))  //初始化边界
        {
            for(int j=0; j<N; j++)
            {
                m_chessboard[i][j] = 2; //"*"
                m_chessboard[j][i] = 2; //"*"
            }
        }

        for( int i=1; i<=SIZE; i++)   //初始化棋盘
        {
            for(int j=1; j<=SIZE; j++)
            {
                m_chessboard[i][j] = 0;
            }
        }

        //初始化三个方向的方向数据
        m_direction[0].x = -1;
        m_direction[0].y = -1;

        m_direction[1].x = 0;
        m_direction[1].y = -1;

        m_direction[2].x = 1;
        m_direction[2].y = -1;

    }

设计一个打印棋盘的函数:

    void print()
    {
        for(m_solution.move(0); !m_solution.end(); m_solution.next())  //遍历解决方案的链表
        {
            cout<< "(" <<m_solution.current().x << "," <<m_solution.current().y<<")";
        }

        cout<<endl;

        for(int i=0; i<N; i++)
        {
            for(int j=0; j<N; j++)
            {
                switch (m_chessboard[i][j])
                {
                    case 0:cout<< " " ;  break;
                    case 1:cout<< "#" ;  break;
                    case 2:cout<< "*" ;  break;
                }
            }

            cout<<endl;
        }

        cout << endl;
    }

实现三个方向上的检查:

    bool check(int x, int y, int d) //检查三个方向上是否有别的皇后
    {
        bool flag = true;

        do  //在当前的位置数据上不停地加上方向数据,来判断
        {
            x += m_direction[d].x;
            y += m_direction[d].y;
            flag = flag &&(m_chessboard[x][y] == 0);  //检查是否有皇后,
        }
        while (flag);//如果为真,则继续检查,直到边界

        return (m_chessboard[x][y] == 2);  //如果为2,则说明直到边界,此方向上都没有别的皇后,x,y已经被加到了边界
    }
检查第j行是否可以放置皇后:
    void run(int j)
    {
        if( j <= SIZE)
        {
            for(int i=1; i<=SIZE; i++)
            {
                if( check(i, j, 0) && check(i, j, 1) && check(i, j, 2))  //判断三个方向是否已经有了皇后
                {
                    m_chessboard[i][j] = 1;

                    m_solution.insert(Pos(i, j));

                    run( j+1 ); //递归调用第J+1行是否可以放皇后

                    m_chessboard[i][j] = 0;  //如果产生回溯,则清空标记

                    m_solution.remove(m_solution.length() -1);
                }
            }
        }
        else //说明前八行都可以放皇后
        {
            m_count++;

            print();
        }
    }

补充构造函数和公有成员函数:

public:
    QueueSolution()
    {
        init();
    }

    void run()
    {
        run(1);  //从第一行开始放置皇后

        cout<< "Total:" <<m_count<<endl;  //打印八皇后问题解决方案的数量
    }
};

注意上述程序中的加黑位置。

测试代码:

int main()
{
    QueueSolution<8> qs;

    qs.run();

    return 0;
}

打印结果请读者自行测试,共92种解法。

程序运行后的栈存储区专供函数调用使用;

栈存储区用于保存实参、局部变量、临时变量等;

利用栈存储区能够方便的实现回溯算法;

八皇后问题是栈回溯的经典应用。















评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值