N皇后问题

算法设计与分析课程实验报告

实验名称:               班级:               学号:             姓名:            指导老师:

  • 实验目的

1.理解回溯法的深度优先搜索策略。

2.掌握用回溯法解决N后问题。

3.掌握用拉斯维加斯算法解决N后问题。

  • 实验关键信息记录

1.拉斯维加斯算法

#include <iostream>

#include <vector>

using namespace std;

const int N = 5;

static int m = 0;

bool check_data(vector<int>& data, int index) {

    //本身就是一个付一个位置的值,然后付下一列的,同一列的不会付两次值,就不用判断是否在同一列

    if (index == 0) return true;

    for (int i = 0; i < index; i++) {

        if (data[index] == data[i])

            //判断是否在一行

            return false;

        if ((index + data[index]) == (i + data[i]))

            //判断斜向上的对角线 (行号+列号)是否相等

            return false;

        if ((index - data[index]) == (i - data[i]))

            //判断斜向下的对角线(行号-列号)是否相等

            return false;}

return check_data(data, index - 1);  //回溯

}

void init_data(vector<int>& data, int index) {

    if (index == N) {

        if (check_data(data, N - 1)) {

            for (int i = 0; i < data.size(); i++) {

                cout << data[i] << " "; }

            m++;

            cout << endl;}

        return;  //递归退出

    }

    if (index > 1) {

        //剪枝优化

        if (!check_data(data, index - 1)) return;}

    //递归穷举

    for (int i = 1; i <= N; i++) {

        data[index] = i;

        init_data(data, index + 1);  //横走

    }}

int main() {

    vector<int> data(N);

    init_data(data, 0);

    cout << "有" << m<< "种解" << endl;

    return 0;}

2.#include <iostream>

using namespace std;

void setChess(int board[7][7], int letter, int num) {                                    //放棋子,同时设置棋子的攻击范围

    if (board[letter][num] != 0) {

        cout << "Here is a chess or here is attacked!\n";

        return;}

    board[letter][num] = 1;

    for (int i = 1; letter + i < 7; i++) {

        board[letter + i][num]--;

        if (num + i < 7)

            board[letter + i][num + i]--;

        if (num - i >= 0)

            board[letter + i][num - i]--;}}

void moveChess(int board[7][7], int letter, int num) {          

//移除棋子,同时调整被攻击范围

    if (board[letter][num] != 1) {

        cout << "Here is no chess!\n";

        return; }

    board[letter][num] = 0;

    for (int i = 1; letter + i < 7; i++) {

        board[letter + i][num]++;

        if (num + i < 7)

            board[letter + i][num + i]++;

        if (num - i >= 0)

            board[letter + i][num - i]++; }}

int findPoint(int board[7][7], int letter, int num) {            

//寻找能放棋子的位置(数字坐标)

    for (int n = num + 1; n < 7; n++) {

        if (board[letter][n] == 0) {

            return n;

            break;

        } }

    return -1;}

bool reback(int board[7][7], int* queen, int& l, int& n) {       

    l--;                                                        //回到上一列

    n = queen[l];                                               //读取当前列的皇后位置

    moveChess(board, l, n);                                     //移除此皇后

    n = findPoint(board, l, n);                                                         //从这一列原皇后位置寻找下一个可放位置

    if (n >= 0 && n < 7) {

        return true;                                                                  //判断这一列是否存在下一个可放位置

    }

    else {                                                      //否则

        if (l > 0) {                                             //若没有回溯到第1列

            queen[l] = -1;                                      //设定此列没有皇后

            return reback(board, queen, l, n);                  //再次回溯

 }else return false;                                                                   //若回溯到第一列,终止回溯,并向主函数传递信息让循环结束

}                                                           

//启用回溯的条件是在该列没有找到其它能放棋子的地方(在主函数中规定)

}

bool nextChess(int board[7][7], int* queen, int& l, int& n) {

    setChess(board, l, n);                                      //在指定位置放棋

    queen[l] = n;                                               //标记棋子的位置

    l++;                                                        //到下一列

    n = findPoint(board, l, -1);                                //寻找能放棋子的位置

    if (n >= 0 && n < 7 && l < 6) {

        return true;                                                                  //如果有,返回真,表示找到了

    }

    else {

        return false;                                                                 //如果没有,返回假,要求主函数回溯

    }

}

void showBoard(int board[7][7]) {                               //打印

    for (int i = 0; i < 7; i++) {

        for (int j = 0; j < 7; j++) {

            if (board[i][j] == 1) cout << " quee";

            else cout << " 1";//用quee表示皇后

        }

        cout << endl;

    }

    cout << endl;

}

int main() {

    int queen[7] = { -1 };

    bool flag;

    int count = 0, l = 0, n = 0;

    int board[7][7] = { 0 };

    while (1) {

        flag = nextChess(board, queen, l, n);                                           //判断下一列是否有放棋子的位置(同时放置棋子)

        if (flag && l < 6) {                                     

//如果有,且还没到最后一列

            continue;

        }

        else if (flag && l == 6) {                             

//如果放棋子放到了最后一列

            count++;                                            //表示找到了一个解

            setChess(board, l, n);                              //放棋子

            showBoard(board);                                   //打印棋谱

            moveChess(board, l, n);                             //移除最后一列的棋子

            reback(board, queen, l, n);                         
//从最后一列开始回溯,寻找下一个解

        }

        else if (!flag)                                      

            flag = reback(board, queen, l, n);                  

//回溯,并判断是否还能回溯

        if (!flag)                                              

//如果不能再回溯即已经没有其它解

            break;                                             

    }

    cout << "有"<<count <<"解法" << endl;

}

运行结果:

1.

2.

  • 实验总结
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值