方法一
#include <cstdio>
#include <cmath>
using namespace std;
/*访问第ithqueen行的每一个位置,如果可行,则修改这个棋子所能控制的位置(并记录这个棋子所在的位置)
此时问题就转换为更小规模的问题 ,当这个子问题解决后,再回复这个棋子所控制的位置,进入下一个同等规模
的问题*/
/*相当于DFS有8个方向,走每一步之前先判断是否到达终点,如果没到,则依次访问每个方向,若可以进入,则记录
当前位置,并更新信息,然后继续朝某条路走,当这个方向的所有路径都走到头时,恢复信息,朝下一个方向走
*/
int count=0;//表明正在记录第count种摆法
int queenplace[92][8];
int board[9][9]={0};
/*对每一个位置先判断再进入,把终止条件放在函数头,这样主要是方便一开始可以直接进入
,函数的形式也可以统一,也就是说不论访问到什么位置,函数的操作都是统一的,不需要对第一个点
或最后一个点之类的位置有特殊的处理。第一次调用是“虚”的,相当于先把问题拆成了相同规模的
8个问题 */
void queen(int ithqueen){
if(ithqueen==8){//如果摆放到第八个皇后,也就是第八行,则这次摆放已经结束
count++;//记录下一种摆法
return;
}
for(int i=0;i<8;i++){//第ithqueen个皇后放在第ithqueen行,遍历这行的每一列,看是否可行
if(board[ithqueen][i]==0){//如果可行的话
for(int k=count;k<92;k++){//记录在第count个及其之后的每种摆法中,之后覆盖
queenplace[k][ithqueen]=i+1;//数组的第ithqueen个位置的值就是第ithqueen行的皇后放在了第几列
}
for(int y=0;y<8;y++){//这个ithqueen所控制的所有格子
for(int x=0;x<8;x++){
if(y==ithqueen||x==i||abs(y-ithqueen)==abs(x-i))
board[y][x]++;
}
}
queen(ithqueen+1);
for(int y=0;y<8;y++){//恢复这个ithqueen所控制的所有格子
for(int x=0;x<8;x++){
if(y==ithqueen||x==i||abs(y-ithqueen)==abs(x-i))
board[y][x]--;
}
}
}
}
}
int main(int argc, char** argv) {
int n,b;
scanf("%d",&n);
queen(0);
while(n--){
scanf("%d",&b);
for(int i=0;i<8;i++) printf("%d",queenplace[b-1][i]);
printf("\n");
}
return 0;
}
方法二
上面的方法用一个二维数组来记录棋盘被已经放置的棋子的控制情况,每次有新的
棋子放置时用了枚举法来判断它控制的范围。还可以用三个一维数组来分别记录每一
列,每个45 度的斜线和每个135 度的斜线上是否已经被已放置的棋子控制,这样每次
有新的棋子放置时,不必再搜索它的控制范围,可以直接通过三个一维数组判断它是否
与已经放置的棋子冲突,在不冲突的情况下,也可以通过分别设置三个一维数组的相应
的值,来记录新棋子的控制范围
不同:方法一在更新信息时比较无脑,时间复杂度更高,但判断条件也就更简单。方法二速度快但是增加了思维复杂度。
#include <stdio.h>
int record[92][9], mark[9], count = 0; //record 记录全部解,mark 记录当前解;
bool range[9], line1[17], line2[17]; //分别记录列方向,45 度,135 度方向上被控制的情况
void tryToPut(int ); //求全部解的过程
void main() {
int i, testtimes, num;
scanf("%d", &testtimes);
for(i = 0; i <=8; i++)
range[i] = true;
for(i = 0; i < 17; i ++)
line1[i] = line2[i] = true;
tryToPut(1);
while(testtimes --) {
scanf("%d", &num);
for(i = 1; i <=8; i++)
printf("%d", record[num - 1][i]);
printf("\n");
}
}
void tryToPut(int i) {
if(i > 8) { //如果最后一个皇后被放置完毕,将当前解复制到全部解中
for(int k = 1; k < 9; k ++)
record[count][k] = mark[k];
count ++;
}
for(int j=1; j<=8; j++) { //逐一尝试将当前皇后放置在不同列上
if(range[j] && line1 [i + j] && line2[i - j + 9]) { //如果与前面的不冲突,
//则把当前皇后放置在当前位置
mark[i] = j;
range[j] = line1[i + j] = line2[i - j + 9] = false;
tryToPut(i + 1);
range[j] = line1[i + j] = line2[i - j + 9] = true;
}
}
}
方法三
也可以直接记录每个已放置的皇后,放后面的皇后时,只要判断和以前的皇后是否冲突即可,不必使用模拟棋盘。