n皇后问题

P1219 [USACO1.5]八皇后 Checker Challenge

版本1:

#include 
using namespace std;
//a[i]存的是第i行的棋子放的列,我们的目标就是把1-n分配给a[1]-a[n],并且不能冲突 
//vis[i][j]=1表示第i行第j列放了棋子,为0表示没放棋子
//vis1[i]=1表示第i列有棋子了,为0表示第i列没有棋子 
int n, a[14], vis[14][14], vis1[14], ans;
//在x行y列放会不会产生冲突 
bool ok(int x, int y)
{
	//定义临时变量,不然x,y的值在一次while判断后就改变了,导致后面的判断失效 
	int tempx, tempy;	
	//判断同一行、同一列有没有冲突 
	//其实没有必要判断行(因为每行只安排一个数),没有必要判断列(vis1[i]表示第i列有没有数字) 
	/*
	for(int i=1; i<=n; ++i){
		if(vis[x][i]==1 || vis[i][y]==1){
			return false;
		}
	}
	*/
	tempx=x;
	tempy=y;
	//判断左下角有没有冲突 
	while(tempx!=n && tempy!=1){
		tempx++;
		tempy--;
		if(vis[tempx][tempy]==1){
			return false;
		}
	}
	tempx=x;
	tempy=y;
	//判断右上角有没有冲突 
	while(tempx!=1 && tempy!=n){
		tempx--;
		tempy++;
		if(vis[tempx][tempy]==1){
			return false;
		}
	} 
	tempx=x;
	tempy=y;
	//判断左上角有没有冲突 
	while(tempx!=1 && tempy!=1){
		tempx--;
		tempy--;
		if(vis[tempx][tempy]==1){
			return false;
		}
	}
	tempx=x;
	tempy=y;
	//判断右下角有没有冲突 
	while(tempx!=n && tempy!=n){
		tempx++;
		tempy++;
		if(vis[tempx][tempy]==1){
			return false;
		}
	}  
	return true;
}
//给第cnt行放棋子  
void dfs(int cnt)
{
	if(cnt==n+1){
		ans++;
		if(ans<=3){	//只输出前三种方案 
			for(int i=1; i<=n; ++i){
				cout << a[i] << " ";
			}
			cout << endl;	
		} 
		return;
	}
	//看第cnt行要放在第几列,i遍历列 
	for(int i=1; i<=n; ++i){
		//如果第cnt行第i列没有放棋子,并且第i列没有放棋子
		//并且在cnt行i列放棋子不会产生冲突,才可以放 
		if(vis[cnt][i]==0 && vis1[i]==0 && ok(cnt, i)){	
			vis[cnt][i]=1;
			vis1[i]=1;
			a[cnt]=i;	
			dfs(cnt+1);
			vis[cnt][i]=0;	
			vis1[i]=0;			
		}
	}
}
int main()
{
	cin >> n;
	dfs(1);
	cout << ans;
	return 0;
}

打印n皇后问题的所有方案,*表示棋子,0表示没放棋子

#include 
using namespace std;
//a[i]存的是第i行的棋子放的列,我们的目标就是把1-n分配给a[1]-a[n],并且不能冲突 
//vis[i][j]=1表示第i行第j列放了棋子,为0表示没放棋子
//vis1[i]=1表示第i列有棋子了,为0表示第i列没有棋子 
int n, a[14], vis[14][14], vis1[14], ans;
//在x行y列放会不会产生冲突 
bool ok(int x, int y)
{
	//定义临时变量,不然x,y的值在一次while判断后就改变了,导致后面的判断失效 
	int tempx, tempy;	
	//判断同一行、同一列有没有冲突 
	//其实没有必要判断行(因为每行只安排一个数),没有必要判断列(vis1[i]表示第i列有没有数字) 
	/*
	for(int i=1; i<=n; ++i){
		if(vis[x][i]==1 || vis[i][y]==1){
			return false;
		}
	}
	*/
	tempx=x;
	tempy=y;
	//判断左下角有没有冲突 
	while(tempx!=n && tempy!=1){
		tempx++;
		tempy--;
		if(vis[tempx][tempy]==1){
			return false;
		}
	}
	tempx=x;
	tempy=y;
	//判断右上角有没有冲突 
	while(tempx!=1 && tempy!=n){
		tempx--;
		tempy++;
		if(vis[tempx][tempy]==1){
			return false;
		}
	} 
	tempx=x;
	tempy=y;
	//判断左上角有没有冲突 
	while(tempx!=1 && tempy!=1){
		tempx--;
		tempy--;
		if(vis[tempx][tempy]==1){
			return false;
		}
	}
	tempx=x;
	tempy=y;
	//判断右下角有没有冲突 
	while(tempx!=n && tempy!=n){
		tempx++;
		tempy++;
		if(vis[tempx][tempy]==1){
			return false;
		}
	}  
	return true;
}
//给第cnt行放棋子  
void dfs(int cnt)
{
	//如果准备给第n+1行放棋子,说明前n行已经放好棋子了,说明本分支方案可行 
	if(cnt==n+1){
		ans++;
		cout << "第" << ans << "种方案:" << endl;
		cout << "   ";
		for(int i=1; i<=n; ++i){
			cout << " " << i << " ";
		}
		cout << endl;
		for(int i=1; i<=n; ++i){
			cout << " " << i << " ";
			for(int j=1; j<=n; ++j){
				if(j==a[i]){
					cout << " * "; 
				}
				else{
					cout << " 0 ";
				}	
			}
			cout << endl;		
		}
		cout << endl;
		return; 
	}
	//看第cnt行要放在第几列,i遍历列 
	for(int i=1; i<=n; ++i){
		//如果第cnt行第i列没有放棋子,并且第i列没有放棋子
		//并且在cnt行i列放棋子不会产生冲突,才可以放 
		if(vis[cnt][i]==0 && vis1[i]==0 && ok(cnt, i)){	
			vis[cnt][i]=1;
			vis1[i]=1;
			a[cnt]=i;	
			dfs(cnt+1);
			vis[cnt][i]=0;	
			vis1[i]=0;			
		}
	}
}
int main()
{
	cin >> n;
	//从第1行开始放棋子 
	dfs(1);
	cout << n << "皇后问题,共有" << ans << "种方案";
	return 0;
}

n皇后问题_第1张图片

另外两种方法:

#include 
using namespace std;
int n,ans,a[20];
int vis[20][20];
void dfs(int x){	//x表示第几行 
	if(x==n+1){
		ans++;
		if(ans<=3){
			for(int i=1;i<=n;++i){
				printf("%d ",a[i]);
			}
			printf("\n");
		}
		return;
	}
	for(int i=1;i<=n;++i){		//列举列数
		if(vis[x][i]==0){
			a[x]=i;
			//右下角对角线打标记 
			for(int j=1;x+j<=n && i+j<=n;++j){
				vis[x+j][i+j]++;
			}
			//对列打标记 
			for(int j=1;j<=n;++j){
				vis[j][i]++;
			}
			//左上角对角线打标记 
			for(int j=1;x-j>=1 && i-j>=1;++j){
				vis[x-j][i-j]++;
			}
			//右上角对角线打标记 
			for(int j=1;x-j>=1 && i+j<=n;++j){
				vis[x-j][i+j]++;
			}
			//左对角线打标记 
			for(int j=1;x+j<=n && i-j>=1;++j){
				vis[x+j][i-j]++;
			}
			dfs(x+1);
			for(int j=1;x+j<=n && i+j<=n;++j){
				vis[x+j][i+j]--;
			}
			for(int j=1;j<=n;++j){
				vis[j][i]--;
			}
			for(int j=1;x-j>=1 && i-j>=1;++j){
				vis[x-j][i-j]--;
			}
			for(int j=1;x-j>=1 && i+j<=n;++j){
				vis[x-j][i+j]--;
			}
			for(int j=1;x+j<=n && i-j>=1;++j){
				vis[x+j][i-j]--;
			}
		}
	}
}
int main(){
	scanf("%d",&n);
	dfs(1);
	printf("%d",ans);
	return 0;
}

#include 
using namespace std;
int n,l[15],temp;
bool vis[5][35];
bool check(int x,int y){
//	for (int i=1;i<=num;++i){
//		if (t[1][i]==x || t[2][i]==y || t[3][i]==a || t[4][i]==b){
//			return 0;
//		}
//	}
	if(vis[1][x] || vis[2][y] || vis[3][x-y+13] || vis[4][x+y]){
		return 0;
	}
	return 1;
}
void ans(int x,int y){
	if (x==n && check(x,y)){
		l[x]=y;
		if (temp<3){
			for (int i=1;i<=n;++i){
				printf("%d ",l[i]);
			}
			printf("\n");
		}
		++temp;
		return;
	}
	if (check(x,y)){
		l[x]=y;
//		x
//		t[1][num]=x;
		//x行打标记 
		vis[1][x]=true;
//		y
//		t[2][num]=y;
		//y列打标记 
		vis[2][y]=true;
//		-
//		t[3][num]=x-y+13;
		//左上到右下对角线标记 
		vis[3][x-y+13]=true;
//		+
//		t[4][num]=x+y;
		//右上到左下对角线标记 
		vis[4][x+y]=true;
		for (int i=1;i<=n;++i){
			ans(x+1,i);
		}
		vis[1][x]=false;
		vis[2][y]=false;
		vis[3][x-y+13]=false;
		vis[4][x+y]=false;
	}
	return;
}
int main(){
	scanf("%d",&n);
	for (int i=1;i<=n;++i){
		ans(1,i);
	}
	printf("%d",temp); 
	return 0;
}

版本2:

n皇后问题_第2张图片

 

#include 
#include
using namespace std;
HANDLE outHandle=GetStdHandle(STD_OUTPUT_HANDLE);
//a[i]存的是第i行的棋子放的列,我们的目标就是把1-n分配给a[1]-a[n],并且不能冲突 
//vis[i][j]=1表示第i行第j列放了棋子,为0表示没放棋子
//vis1[i]=1表示第i列有棋子了,为0表示第i列没有棋子 
int n, a[14], vis[14][14], vis1[14], ans;
char asd=1;
//在x行y列放会不会产生冲突 
bool ok(int x, int y)
{
	//定义临时变量,不然x,y的值在一次while判断后就改变了,导致后面的判断失效 
	int tempx, tempy;	
	tempx=x;
	tempy=y;
	//判断左下角有没有冲突 
	while(tempx!=n && tempy!=1){
		tempx++;
		tempy--;
		if(vis[tempx][tempy]==1){
			return false;
		}
	}
	tempx=x;
	tempy=y;
	//判断右上角有没有冲突 
	while(tempx!=1 && tempy!=n){
		tempx--;
		tempy++;
		if(vis[tempx][tempy]==1){
			return false;
		}
	} 
	tempx=x;
	tempy=y;
	//判断左上角有没有冲突 
	while(tempx!=1 && tempy!=1){
		tempx--;
		tempy--;
		if(vis[tempx][tempy]==1){
			return false;
		}
	}
	tempx=x;
	tempy=y;
	//判断右下角有没有冲突 
	while(tempx!=n && tempy!=n){
		tempx++;
		tempy++;
		if(vis[tempx][tempy]==1){
			return false;
		}
	}  
	return true;
}
//给第cnt行放棋子  
void dfs(int cnt)
{
	
	//如果准备给第n+1行放棋子,说明前n行已经放好棋子了,说明本分支方案可行 
	if(cnt==n+1){
		ans++;
		//只输出一种方案 
//		if(ans>1)	return;
		cout << "第" << ans << "种方案:" << endl;
		cout << "    ";
		for(int i=1; i<=n; ++i){
			cout << " " << i << "  ";
		}
		cout << endl << "   -";
		for(int i=1; i<=n; ++i){
			cout << "----";
		}
		cout << endl;
		for(int i=1; i<=n; ++i){
			cout << " " << i << " |";
			for(int j=1; j<=n; ++j){
				if(j==a[i]){
					SetConsoleTextAttribute(outHandle,0x0f);
					cout << " " << asd;
					SetConsoleTextAttribute(outHandle,0x07);
					cout << " |"; 
				}
				else{
					cout << "   |";
				}	
			}
			cout << endl << "   -";
			for(int i=1; i<=n; ++i){
				cout << "----";
			}
			cout << endl;	
		}
		cout << endl;
		return; 
	}
	//看第cnt行要放在第几列,i遍历列 
	for(int i=1; i<=n; ++i){
		//如果第cnt行第i列没有放棋子,并且第i列没有放棋子
		//并且在cnt行i列放棋子不会产生冲突,才可以放 
		if(vis[cnt][i]==0 && vis1[i]==0 && ok(cnt, i)){	
			vis[cnt][i]=1;
			vis1[i]=1;
			a[cnt]=i;	
			dfs(cnt+1);
			vis[cnt][i]=0;	
			vis1[i]=0;			
		}
	}
}
int main()
{
	cin >> n;
	//从第1行开始放棋子 
	dfs(1);
	cout << n << "皇后问题,共有" << ans << "种方案" << endl;
	return 0;
}

另一种实现方法

#include 
#include
using namespace std;
HANDLE outHandle=GetStdHandle(STD_OUTPUT_HANDLE);
//a[i]存的是第i行的棋子放的列,我们的目标就是把1-n分配给a[1]-a[n],并且不能冲突 
//visl[i]=1表示第i列有棋子了,为0表示第i列没有棋子 
//djx1[i]和djx2[i]表示对角线是否有棋子 
int n, a[30], ans, visl[30], djx1[100], djx2[100];;
char asd=1;
void dfs(int cnt)
{ 
	//如果准备给第n+1行放棋子,说明前n行已经放好棋子了,说明本分支方案可行 
	if(cnt==n+1){
		ans++;
		//只输出一种方案 
		if(ans>1)	return;
		cout << "第" << ans << "种方案:" << endl;
		cout << "    ";
		for(int i=1; i<=n; ++i){
			cout << " " << i << "  ";
		}
		cout << endl << "   -";
		for(int i=1; i<=n; ++i){
			cout << "----";
		}
		cout << endl;
		for(int i=1; i<=n; ++i){
			cout << " " << i << " |";
			for(int j=1; j<=n; ++j){
				if(j==a[i]){
					SetConsoleTextAttribute(outHandle,0x0f);
					cout << " " << asd;
					SetConsoleTextAttribute(outHandle,0x07);
					cout << " |"; 
				}
				else{
					cout << "   |";
				}	
			}
			cout << endl << "   -";
			for(int i=1; i<=n; ++i){
				cout << "----";
			}
			cout << endl;	
		}
		cout << endl;
		return; 
	}
	for(int i=1; i<=n; ++i){
		if(!visl[i] && !djx1[cnt+i] && !djx2[n+cnt-i]){
			visl[i]=djx1[cnt+i]=djx2[n+cnt-i]=true;
			a[cnt]=i;
			dfs(cnt+1);
			visl[i]=djx1[cnt+i]=djx2[n+cnt-i]=false;
		}
	}
}
int main()
{
	scanf("%d", &n);
	dfs(1);
	cout << n << "皇后问题,共有" << ans << "种方案" << endl;
	return 0;
}

你可能感兴趣的:(NOIP,蓝桥杯,fpga开发,拓扑学)