1. 程式人生 > >N-皇后的回溯解法

N-皇后的回溯解法

回溯演算法的基本思想是:從一條路往前走,能進則進,不能進則退回來,換一條路再試。
#include <stdio.h>
#include <math.h>
#include <stdlib.h>    

#define N_size 7
#define INITIAl -1000

int N=N_size;
int count = 0;

void init(int a[])
{
	int *p = a;
	for(int i = 0; i<=N_size; i++)
	{
		*p = INITIAl;
		p++;
	}
}


void Print(int a[])
{
	for(int i = 0; i<=N-1; i++)
	{
		//printf("第%d行, a[i]  is:%d\n",i, a[i]);
		for(int j = 0; j<=N-1; j++)
		{
			if(a[i] == j)
				printf(" #");
			else
				printf(" .");
		}
		printf("\n");
	}

}

bool can_place(int i, int j, int a[])
//判斷第i行, 第j列是否可以放置皇后
{
	for(int m = 0; m<=N-1; m++)
	{
		//printf("第 %d 行, 第%d 列, a[m] is: %d.\n", i, j, a[m]);
		if((a[m] == j) || (abs(a[m] - j) == abs(m-i)))
			return false;

	}
	return true;


}


void queens(int N, int i, int a[])
{
	//往第i行放置皇后:前i-1行已經放好
	if(i == N)
		//it's time to print the result
	{
		Print(a);
		count++;

	}
	else
	{
		for(int j = 0; j<=N-1; j++)
		{
			if(a[i] == INITIAl)  //若a[i]的值為initial, 則說明第i行還沒有放置皇后
			{
				if(can_place(i, j, a))
				{
					printf("可以往第%d行 第%d列 放置皇后\n",i, j);
					a[i] = j;  //place at (i,j):第i行, 第j列
					queens(N, i+1, a);//繼續往第i+1行放置皇后

					//如果在第i行第j列放置皇后之後, 能繼續探索到第i+1行的皇后放置位置, 並最終找到在第N-1行放置皇后的位置, 則會輸出最終結果
					//否則, 假設在第i+1行就找不到合適的位置,則queens(N, i+1, a)函式會什麼也不輸出, 並返回到這裡的a[i] = INITIAl
					//意味著取消之前的第i行位置, 從下一個j進行判斷, 判斷第i行第j+1列是否可以放置

					a[i] = INITIAl;//這一句實現回溯到上一層
				}
			}
		}
	}

}

int main()
{
	int a[N_size];
	//需要在防止皇后前對a進行初始化, 且每個元素值都是負數, 否則會自動初始化為全0, a[0] = 0,即預設將第0行的皇后放在了第一列
	init(a);

	queens(N_size, 0, a);
	printf("共有%d種解法.", count);
}
a[N_size]用來儲存每一行皇后所在列數,a[4]=4代表第四行的皇后放在第4列.