百练#2754八后问题

描述
会下国际象棋的人都很清楚:皇后可以在横、竖、斜线上不限步数地吃掉其他棋子。如何将8个皇后放在棋盘上(有8 * 8个方格),使它们谁也不能被吃掉!这就是著名的八皇后问题。
对于某个满足要求的8皇后的摆放方法,定义一个皇后串a与之对应,即a=b1b2…b8,其中bi为相应摆法中第i行皇后所处的列数。已经知道8皇后问题一共有92组解(即92个不同的皇后串)。
给出一个数b,要求输出第b个串。串的比较是这样的:皇后串x置于皇后串y之前,当且仅当将x视为整数时比y小。
输入
第1行是测试数据的组数n,后面跟着n行输入。每组测试数据占1行,包括一个正整数b(1 <= b <= 92)
输出
输出有n行,每行输出对应一个输入。输出应是一个正整数,是对应于b的皇后串。
样例输入

2
1
92

样例输出

15863724
84136275

#include<iostream>
#include<cmath>
#include<cstring>
using namespace std;
int result[93][9];
int used[9][9];
int cnt;
void que(int n){
	int i,j;
	if(n == 9){
		++cnt;
		return;
	}
	else{
		for(i = 1;i <= 8; ++i){
			if(used[n][i] == 0){
				for(j = cnt;j <= 92; ++j)
					result[j][n] = i;
				for(j = 1;j <= 8; ++j)
					if(used[n][j] == 0)
						used[n][j] = n;
				for(j = 1;j <= 8; ++j)
					if(used[j][i] == 0)
						used[j][i] = n;
				for(j = 1;j <= 7; ++j){//直接改同列同行上斜下斜......
					if((n + j) >= 1 && (n + j) <= 8 && (i + j) >= 1 && (i + j) <= 8)
						if(used[n+j][i+j] == 0)
							used[n+j][i+j] = n;
					if((n + j) >= 1 && (n + j) <= 8 && (i - j) >= 1 && (i - j) <= 8)
						if(used[n+j][i-j] == 0)
							used[n+j][i-j] = n;
					if((n - j) >= 1 && (n - j) <= 8 && (i + j) >= 1 && (i + j) <= 8)
						if(used[n-j][i+j] == 0)
							used[n-j][i+j] = n;
					if((n - j) >= 1 && (n - j) <= 8 && (i - j) >= 1 && (i - j) <= 8)
						if(used[n-j][i-j] == 0)
							used[n-j][i-j] = n;
				}
				que(n + 1);
				for(j = 1;j <= 8; ++j)
					if(used[n][j] == n)
						used[n][j] = 0;
				for(j = 1;j <= 8; ++j)
					if(used[j][i] == n)
						used[j][i] = 0;
				for(j = 1;j <= 7; ++j){
					if((n + j) >= 1 && (n + j) <= 8 && (i + j) >= 1 && (i + j) <= 8)
						if(used[n+j][i+j] == n)
							used[n+j][i+j] = 0;
					if((n + j) >= 1 && (n + j) <= 8 && (i - j) >= 1 && (i - j) <= 8)
						if(used[n+j][i-j] == n)
							used[n+j][i-j] = 0;
					if((n - j) >= 1 && (n - j) <= 8 && (i + j) >= 1 && (i + j) <= 8)
						if(used[n-j][i+j] == n)
							used[n-j][i+j] = 0;
					if((n - j) >= 1 && (n - j) <= 8 && (i - j) >= 1 && (i - j) <= 8)
						if(used[n-j][i-j] == n)
							used[n-j][i-j] = 0;
				}
			}
		}
	}
}
int main(){
	int i,j,N;
	int pos[92];
	scanf("%d",&N);
	for(i = 0;i < N; ++i){
		scanf("%d",pos + i);
	}
	memset(used,0,sizeof(used));
	cnt = 1;
	que(1);
	for(i = 0;i < N; ++i){
		for(j = 1;j <= 8; ++j)
			printf("%d",result[pos[i]][j]);
		printf("\n");
	}
	return 0;
}

思路一:使用二维数组保存每个位置是否可以使用。

#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
int shu[9],sx[17],xx[17];
int result[93][9];
int cnt;
void que(int n){
	int i,j;
	if(n == 9){
		cnt++;
		return;
	}
	else{
		for(i = 1;i <= 8; ++i){
			if((!shu[i]) && (!sx[n + i]) && (!xx[n - i + 8])){
				for(j = cnt;j <= 92; ++j){
					result[j][n] = i;
				}
				shu[i] ^= 1;
				sx[n + i] ^= 1;
				xx[n - i + 8] ^= 1;
				que(n + 1);
				shu[i] ^= 1;
				sx[n + i] ^= 1;
				xx[n - i + 8] ^= 1;
			} 
		}
	}
}
int main(){
	int N,i,j;
	int pos[93];
	scanf("%d",&N);
	for(i = 0;i < N; ++i)
		scanf("%d",pos + i);
	cnt = 1;
	memset(shu,0,sizeof(shu));
	memset(sx,0,sizeof(sx));
	memset(xx,0,sizeof(xx));
	que(1);
	for(i = 0;i < N; ++i){
		for(j = 1;j <= 8; ++j){
			printf("%d",result[pos[i]][j]);
		}
		printf("\n");
	}
	return 0;
} 

思路二:使用三个数组保存各列号是否被使用。

#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
int shu[9],result[93][9];
int cnt;
void que(int n){
	int i,j;
	if(n == 9){
		for(i = 1;i <= 8; ++i)
			result[cnt][i] = shu[i];
		++cnt;
	}
	else{
		for(i = 1;i <= 8; ++i){
			for(j = 1;j < n; ++j){
				if(shu[j] == i || abs(n - j) == abs(shu[j] - i))
					break;
			}
			if(j == n){
				shu[n] = i;
				que(n + 1);
			}
		}
	}
}
int main(){
	int N,i,j;
	int pos[93];
	scanf("%d",&N);
	for(i = 0;i < N; ++i)
		scanf("%d",pos + i);
	cnt = 1;
	que(1);
	for(i = 0;i < N; ++i){
		for(j = 1;j <= 8; ++j)
			printf("%d",result[pos[i]][j]);
		printf("\n");
	}
	return 0;
} 

思路三:直接使用一个数组(下标为行号)保存之前各行的列数。

八后规模还是太小,三种方法运行时间区别不大。

关于八后问题的一点感悟:
ACM不单是刷题呐,紫书上说,八后问题本质上就是一个全排列问题(列号的全排列 8!种情况),而且还没有重复元素,优化的地方就是回溯的条件。回溯一定要在所有递归函数出口处恢复被修改的值。

发布了53 篇原创文章 · 获赞 0 · 访问量 730

猜你喜欢

转载自blog.csdn.net/weixin_38894974/article/details/104291850