[原创]八皇后问题

八皇后问题是一个经典的问题了。需求自行搜索

先上git库 https://git.oschina.net/jasonbu/queen.git


需求分解:

1、根据需要,N皇后总共有N*N个点可以尝试

2、根据要求,每行,每列,还有两条45度的斜线都不允许有重复的皇后存在

3、要求算出所有的可能性,如果有可能,保存所有的可能性


大致思路就是:

1、列优先,行其次,如果当前坐标安全,则判定下一列有没有安全的坐标。

2、如果当前列穷举完成,回溯

3、如果当前完成的列是第一列,则整个运算完成


代码实现:

首先很自然的想到了穷举法,之前不太了解回溯的概念,在回溯上走了很多弯路,不过后来想到如果每次放置的点都是安全点的话,在回溯的时候可以自然移除。所以在回溯的工作量上减小了很多,只需要保存之前保存的N-1个点,在回溯的时候就可以完美还原现场。

同时,因为初步实现未考虑保存,使用一个数组完成类似PUSH和POP就可以实现还原。

当然,也考虑到了,如果需要记录结果,在每次record()调用时保存ans[]即可




代码:

//file: main.cpp


#include <iostream>
#include <cstdint>
#include <ctime>

/*
	x:	列坐标		(column)
	y:	行坐标		(row)
	p:	斜线控制	(45度 1 3 象限)
	q;	斜线控制	(135度 2 4象限)
	*/

const uint32_t __max = 16;
uint32_t __cnt;


bool y_rec[__max];				//记录当前已经不安全的y
bool p_rec[2 * __max - 1];		//记录当前已经不安全的p
bool q_rec[2 * __max - 1];		//记录当前已经不安全的q
uint32_t ans[__max];			//记录当前已经通过的序列

inline uint32_t x_y_to_p(uint32_t x, uint32_t y)
{
	return x + y;
}
inline uint32_t x_y_to_q(uint32_t x, uint32_t y)
{
	return (__max - 1) + x - y;
}
//return true:safe
//return false:refused
bool try_set(uint32_t x, uint32_t y)
{
	bool* p_y = y_rec + y;
	if (*p_y){
		return false;
	}

	bool* p_p = p_rec + x_y_to_p(x, y);
	if (*p_p){
		return false;
	}

	bool* p_q = q_rec + x_y_to_q(x, y);
	if (*p_q){
		return false;
	}

	*p_y = true;
	*p_p = true;
	*p_q = true;
	return true;

}
inline void record()
{
	//如果需要记录的话,在这里再处理
	__cnt++;
}

inline void remove(uint32_t x, uint32_t y)	//next ans
{
	y_rec[y] = false;
	p_rec[x_y_to_p(x, y)] = false;
	q_rec[x_y_to_q(x, y)] = false;
}

void calculation(uint32_t x, uint32_t y)
{
	for (;;){							//用于控制当前列是否为第一列的最后一个穷举
		for (; y < __max;){				//如果当前列穷举到最后一行,跳出循环
			if (try_set(x, y)){			//如果当前坐标安全
				ans[x] = y;			//记录坐标,用于回溯
				if (x >= __max - 1){		//如果当前是最后一列
					record();				//记录当前结果
					remove(x, y);			//移除当前坐标

					x--;					//回溯上一列
					y = ans[x];			//回溯上一列到了第几行
					remove(x, y);			//回溯
					y++;					//下一行
				}
				else{						//当前不是最后一列
					x++;					//移动到下一列
					y = 0;					//从第一行开始重新穷举
				}
			}
			else{						//当前行位置不安全
				y++;					//切换到下一行
			}
		}
		if (x == 0){				//第一列穷举到最后一行
			break;					//穷举结束
		}
		else{						//某一列穷举结束
			x--;					//回溯上一列
			y = ans[x];			//回溯上一列到了第几行
			remove(x, y);			//回溯
			y++;					//下一行
		}
	}
}

void calc(void)
{
	uint32_t x, y;
	if (__max == 1){
		__cnt = 1;
		return;
	}
	x = 0;
	y = __max / 2;
	calculation(x, y);
	__cnt *= 2;
}

int main(void)
{
	uint32_t queen_cnt = 16;

	time_t start;
	time_t end;


	time(&start);
	calc();
	time(&end);

	;

	std::cout << "queen_cnt:"
		<< queen_cnt
		<< "\nresult:"
		<< __cnt
		<< "\ntime_use: "
		<< end - start
		<< std::endl;
	std::cin.get();

	return 0;
}



另外,git库中还有两个分支

master分支为最开始用类实现的,不过效率略低

Jeff_Somers分支为目前公认的最快算法,使用了位运算


PS:    master_use_c_static分支在4.4G主频上运算16皇后使用了25秒。个人还是满意的。

PPS:Jeff_Somers分支在4.4G主频上运算16皇后使用了4秒...




你可能感兴趣的:(C++,c,算法,八皇后)