八皇后问题

    八皇后问题,是一个古老而著名的问题,是回溯算法的典型案例。该问题是国际西洋棋棋手马克斯·贝瑟尔于1848年提出:在8X8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。百度百科解释

八皇后问题

     一般看到这种图,大家第一感觉肯定是用一个二维数组来表示出坐标信息,但此处,感觉题目进行分析,8X8的棋盘上摆放8个皇后,且不能同行、同列和同一斜线上,那么也就是说每行最多一个皇后。因此我们仅用一个长度为8的数组就可以表示出皇后的位置信息,该数组的索引N即为第N行,索引对应的值即为第N行皇后所处的列数。

    另外,对于该问题,也不能简单的进行遍历,因为时间复杂度为8*8*8*8*8*8*8*8*8,8的8次方。换个角度:

    1,在第N行放置皇后,只需要判断前N-1行皇后的位置与第N行皇后的关系,那么剩下的8-N行在这个循环中是不需要判断的(因为此时剩下的行还没有皇后啊^_^)。如果第N行放置成功,则在此基础上尝试放置第N+1行的皇后;

    2,如果第N行放置失败,则要回溯到第N-1行,重新选择第N-1行皇后所处的列数。如果第N-1行依然放置失败,则再回溯到第N-2行,以此类推;

    3,如果第N行为最后一行了,则说明完全成功,打印整个棋盘。

#include <stdio.h>
#include <malloc.h>
#include <stdio.h>                
#include <math.h>
#include <string.h>
#include <stdlib.h>

// 打印整个阵列
void printPos(const int *pos, const int cnt)
{
#define QUEEN 		'#'
#define NOT_QUEEN	'*'

	// 记录共有多少组满足条件的组合。
	static int total = 0;
	
	printf("case %d:\n", ++total);
	for(int i = 0; i < cnt; ++i){
		for(int j = 0; j < cnt; ++j){
			if(pos[i] != j){
				printf("%c ", NOT_QUEEN);
			}else{
				printf("%c ", QUEEN);
			}
		}
		printf("\n");
	}
	printf("\n");
}

// 尝试在第row行插入的第col列插入值
int tryInsertPos(int* pos, const int cnt, int row, int col)
{
	for(int i = 0; i < row; ++i){
		int otherRow = i;	// row行之上的皇后所处的行数。
		int otherCol = pos[otherRow];	// row行之上的皇后所处的lie数。
		// 不能在同一列。
		if(col == pos[otherRow]){
			return -1;
		}
		
		// 不能在对角线上。
		if(abs(col - otherCol) == abs(row - otherRow)){
			return -1;
		}
	}
	
	pos[row] = col;
	
	// 最后一行,已经满足条件了。
	if(cnt == row + 1){
		printPos(pos, cnt);
		return 0;
	}else{
		int ret = 0;
		// 尝试在下一行的各个位置放置皇后。
		for(int i = 0; i < cnt; ++i){
			ret = tryInsertPos(pos, cnt, row + 1, i);
			if(ret != 0){
				continue;
			}
		}
		
		return ret;
	}
}

int main(int argc, char** argv)
{
	int CNT = 8;
	if(argc == 2){
		CNT = atoi(argv[1]);
	}	
	
	// 数组的索引为皇后所在的行数,索引对应的值表示该皇后对应的列数。
	// 如pos[1] = 2,则表示在第二行第三列存在皇后。
	int *pos = (int*)malloc(sizeof(int) * CNT);
	if(NULL == pos){
		printf("line %d malloc error\n", __LINE__);
		return -1;
	}
	memset(pos, 0, sizeof(int) * CNT);
	
	//tryInsertPos(pos, CNT, 0, 0);
	
	for(int i = 0; i < CNT; ++i){
		tryInsertPos(pos, CNT, 0, i);
	}
	
	
	free(pos);
	return 0;
}

你可能感兴趣的:(八皇后问题)