算法设计与分析课程实验报告
实验名称: 班级: 学号: 姓名: 指导老师:
- 实验目的
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.
- 实验总结