##备注:这次有六道题目,所以分成三次来写题目
这两题都涉及到了剪枝法加回溯法,这次题目比较难,我也不太懂其实,讲的不好附上我在网上找到的优秀解析的链接,建议看别人的解析好点。
第一次:https://blog.csdn.net/lil_junko/article/details/92759922
第二次:https://blog.csdn.net/lil_junko/article/details/92759977
题目(1)
时间限制: 1000 ms 内存限制: 64 MB 代码长度限制: 16 KB
给定一个n×n的棋盘和n个皇后,要求在棋盘上放置n个皇后使得任意两皇后的位置满足不同行、不同列且不在同一条对角线(斜率为45度或135度的直线)上,这样的放置位置构成问题的一个解。现约定第1个皇后放置在棋盘的第1行、第2个皇后放置在棋盘的第2行、… 、第n个皇后放置在棋盘的第n行。下图是n=8的情形。因此,n个皇后的一种放置位置可用每个皇后放置位置的列号序列来表示。要求快速给出n皇后问题的一个解。
输入格式: 输入为在一行中给出一个正整数n(8≤n≤100)。
输出格式: 对每一个输入n,在一行中输出问题的一个解(即这n个皇后放置位置的列号序列)。如果问题有多个解,输出任意一个解即可;如果问题没有解,则输出0。
输入样例: 8
输出样例: 4 6 8 2 7 1 3 5
简单解析
他人的优秀解答:https://www.cnblogs.com/fstang/archive/2013/05/12/3073598.html
1.用随机的思想初始化放置结果(随机找到其中一个位置才开始删枝)。
2.处于同一对角线的位置进行标记,如点C(u,v) , u+v 和 |u-r| 这两个方向进行标记,这样可以快速查找是否满足所有对角线不存在两个皇后(详情可见《算法竞赛入门经典第二版》刘汝佳著的P193)
3.在根据上面的一步步调整解,直至没有冲突(指存在两个皇后能互相攻击的情况)
(但是为什么这样可以迭代步数变成这么少,也没有解释,如果有证明的方法或者过程,请麻烦发我一份,谢谢)
代码
#include <cstdio>
#include <cstdlib>
#include <ctime>
#define MAX 1000 //最多可能皇后数
#define swap(a,b) {int t = a; a = b; b = t;}
//row[i]表示当前摆放方式下第i行的皇后数,col[i]表示当前摆放方式下第i列的皇后数
int row[MAX];
int col[MAX];
int N; //放置N个皇后在N*N棋盘上
//从左上到右下的对角线上row-col值是相同的,但是这个值有可能是负值,最小为-(N-1),
//所以可以做个偏移,统一加上N-1,这样这个值就在[0,2*N-2]范围内,将这个值作为该对角线的编号
//pdiag[i]表示当前摆放方式下编号为i的对角线上的皇后数
int pdiag[2 * MAX];//principal diagonal,主对角线,左上到右下(表示和主对角线平行的2N-1条对角线)
//从右上到左下的对角线row+col的值相同,取值范围为[0, 2 * MAX - 2],作为对角线编号
//cdiag[i]表示编号为i的对角线上的皇后数
int cdiag[2 * MAX];//counter diagonal,副对角线
//R[]用来存储皇后放置位置,R[row] = col表示(row,col)处,即“第row行第col列”有个皇后
int R[MAX];
//给定二维矩阵的一个点坐标,返回其对应的左上到右下的对角线编号
int getP(int row, int col) {
return row - col + N - 1;
}
//给定二维矩阵的一个点坐标,返回其对应的右上到左下的对角线编号
int getC(int row, int col) {
return row + col;
}
//返回begin, begin + 1, ... , end - 1 这end - begin个数中的随机的一个
int my_rand(int begin, int end) {//左闭右开[begin, end)
return rand() % (end - begin) + begin;
}
//原地shuffle算法,算法导论中的randomize in place算法
void randomize(int a[], int begin, int end)// 左闭右开
{
for(int i = begin; i <= end - 2; i++){
int x = my_rand(i, end);
swap(a[i], a[x]);
}
}
//初始化皇后的摆放,同时初始化row,col,pdiag,cdiag数组
void init()
{
for(int i = 0; i < N; i++){//N queens
R[i] = i;
}
randomize(R, 0, N);//初始化N个皇后对应的R数组为0~N-1的一个排列,即没有任意皇后同列,也没有任何皇后同行
for(int i = 0; i < N; i++){
row[i] = 1;//每行恰好一个皇后
col[i] = 0;
}
for(int i = 0; i < 2 * N - 1; i++){//N queens
pdiag[i] = 0;
cdiag[i] = 0;
}
for(int i = 0; i < N; i++){//N queens
col[R[i]]++;
pdiag[getP(i, R[i])]++;
cdiag[getC(i, R[i])]++;
}
}
bool adjust_row(int row);
void print_result();
bool qualify();
int main(int argc, const char *argv[])
{
srand((unsigned)time(NULL));
scanf("%d", &N);
init();
if (qualify()) {//运气很好,初始化后就满足终止条件
print_result();
return 0;
}
bool can_terminate