最近因为接触了最短路径问题所以开始了解dfs和bfs,从dfs开始就是熟悉的八皇后问题。

大家都很清楚八皇后问题主要是将八个皇后分在一个8*8的格子内,然后每个皇后所在的行、列、主对角线和副对角线都不能有其他皇后存在,故这就需要采用一个个判断问题了。

也许有些人想从二维数组方面入手。但是想到的是,每次将某个皇后位置定下后,对其所在的行、列、主对角线和副对角线都要置false,对其所在行、列、主对角线和副对角线都置false将提高复杂度,而且当某次放置所有皇后并不成立,那么就要对二维数组全部置true后重新开始(对第一次放的皇后位置置false),这将十分麻烦。

所以我们可以从其内部入手。

我们定义一个一位数组,默认从行开始,这样就可以避免行冲突,然后将一位数组值置为列值,如果某两个不同行的列值相同,则其列冲突,不符合。

那么对于主对角线和副对角线呢

我们这里介绍一个小技巧,

 1  2  3  4
 5  6  7  8
 9 10 11 12
13 14 15 16

如上是一个4*4的矩阵,

我们可以得知如果一些数字在一条主对角线上,其行列之差相同,

如1(1,1) 6(2,2) 11(3,3) 12(4,4)行列之差均为0,所以我们可以在判断时这样写

judge[x]-x = judge[y]-y,这可以作为一个判断条件

 

那么相应的副对角线,你会发现一条副对角线的所有位置行列之和相同

如4(1,4)7(2,3) 10(3,2) 13(4,1)行列之和均为5,所以这时我们这么判断

judge[x]+x = judge[y]+y,这同样也是一个判断条件

 

这时候也许你会疑惑怎么解决判断的范围问题,那么我们只要判断当前行的上面所有行即可

即我们判断时范围限制在current前所有行。

下面是一个八皇后的总放置方式的代码

#include<stdio.h>
int n = 8;
int judge[8];
int total;
int check(int cur){
	for(int i = 0; i < cur; i++)
		if(judge[i] == judge[cur] || judge[i]+i == judge[cur]+cur || judge[i]-i == judge[cur]-cur) //依次是列、副对角线、主对角线的判断 
			return 0;
	return 1;
}
void dfs(int cur){
	if(cur == n)
		total++;//因为我们是判断0~7的,如果到达了n=8,即所有放置完成。此种方式合适 
	else{
		for(int i = 0; i < n; i++){
			judge[cur] = i; //先判断cur行i列 ,每次cur行放置时,都是从其0列开始的。 
			if(check(cur))
				dfs(cur+1);//如果符合条件,则向下继续放置 
		}
	}
	 
}
int main()
{
	dfs(0);
	printf("%d\n", total);
	return 0;
}

 

 

那么下一个问题就是,我们该如何输出这么些放置呢,输出所有的排列矩阵,排列皇后即输出1,否则输出0

代码及注释:

#include<stdio.h>
int n = 8;
int judge[9];
int total;
int out[9][9];//输出数组 
int check(int cur){
	for(int i = 0; i < cur; i++)
		if(judge[i] == judge[cur] || judge[i]+i == judge[cur]+cur || judge[i]-i == judge[cur]-cur)
			return 0;
	return 1;
}
void dfs(int cur){
	if(cur == n){ 
		total++; 
		printf("No.%d\n", total); //符合条件即输出 
		for(int i = 0; i < n; i++){ 
			for(int j = 0; j < n; j++)
				printf("%d ", out[i][j]);
			printf("\n");
		}
		printf("\n");
	} 
	else{
		for(int i = 0; i < n; i++){
			judge[cur] = i; 
			if(check(cur) && out[cur][i] != 1){
				out[cur][i] = 1; //符合条件的位置置1 
				dfs(cur+1);
				out[cur][i] = 0; //递归结束后依次置0 
			} 
		}
	}
	 
}
int main()
{
	dfs(0);
	return 0;
}

输出每行所放置的皇后列代码:

#include<stdio.h>
int n = 8;
int judge[9];
int total;
int out[9][9];//输出数组 
int check(int cur){
	for(int i = 0; i < cur; i++)
		if(judge[i] == judge[cur] || judge[i]+i == judge[cur]+cur || judge[i]-i == judge[cur]-cur)
			return 0;
	return 1;
}
void dfs(int cur){
	if(cur == n){ 
		total++; 
		printf("No.%d\n", total); //符合条件即输出 
		for(int i = 0; i < n; i++){ 
			for(int j = 0; j < n; j++){ 
				if(out[i][j] == 1)
					printf("%d ", j+1);
				else
					printf("%d ", out[i][j]);
			} 
			printf("\n");
		}
		printf("\n");
	} 
	else{
		for(int i = 0; i < n; i++){
			judge[cur] = i; 
			if(check(cur) && out[cur][i] != 1){
				out[cur][i] = 1; //符合条件的位置置1 
				dfs(cur+1);
				out[cur][i] = 0; //递归结束后依次置0 
			} 
		}
	}
	 
}
int main()
{
	dfs(0);
	return 0;
}