1、问题描述
八皇后问题是一个以国际象棋为背景的问题:如何能够在 8×8 的国际象棋棋盘上 放置八个皇后,使得任何一个皇后都无法直接吃掉其他的皇后?为了达到此目的,任两个皇后都不能处于同一条横行、纵行或斜线上。八皇后问题可以推广为更一般的n皇后摆放问题:这时棋盘的大小变为n1×n1,而皇后个数也变成n2。而且仅当 n2 ≥ 1 或 n1 ≥ 4 时问题有解。
2、n皇后问题的解决
我们以4皇后的例子来讲,在一个4*4的棋盘当中,因为要保证不在同一行,所以每一行只可以放置一个皇后,这里我使用的是dfs来遍历,每次遍历一行,在遍历的同时也要判断当前位置是否可以放置棋子,此时就需要我们来判断是否存在棋子和当前准备放置的棋子处于同一个列和对角线上面。这里判断列是比较简单的,循环到当前行然后,每一行的该列是否存在有放置过棋子;对于角线的判断来说对行一依旧是循环到当前行,但是列需要遍历全部列号,因为有着主对角线和次对角线的存在,这里我是通过斜率来进行判断的,主对角线位-1,次对角线为1;假设这里我们要判断row行col列的元素是否可以放置,如果我们遍历到了x行y列的元素如果col-y/row-x=-1或者是col-y/row-x=1,这就说明从开始到这一行存在一个放置元素的位置与row行col列的这个位置成对角线。
(在这里我是让棋盘上的位置都可以放置,不存在不可以放置棋子的位置)
/***这一部分是判断该位置是否危险
int Isdangerous(int row,int col)
{
for(int i=0;i<row;i++)
{
if(num[i][col]==1) //判断列
{
return 0;
}
for(int j=0;j<n;j++)
{
if(num[i][j]==1)
{
if((i-j==row-col)||(col+row==i+j))//判断对角线
return 0;
}
}
}
return 1;
}
/****DFS深度遍历棋盘
void GetChess(int ith)//ith是当前遍历的行
{
if(ith==n)
{
sum++;
cout<<"第"<<sum<<"种"<<endl;
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
cout<<num[i][j]<<' ';
}
cout<<endl;
}
return ;
}
for(int i=0;i<n;i++)
{
if(Isdangerous(ith,i)==1)
{
num[ith][i]=1;
GetChess(ith+1);
num[ith][i]=0;//进行回溯
}
}
}
```cpp
#include<iostream>
using namespace std;
int n;//皇后个数
int num[20][20];//定义的棋盘
int sum=0;//定义的放置的方法种类
void init()//初始化棋盘
{
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
num[i][j]=0;
}
int main()
{
cin>>n;
init();
GetChess(0);//从第0行开始遍历
return 0;
}
2、2n皇后问题
n皇后问题解决了之后,对于2n就好解决了很多,我们只需要在n皇后的基础上在去进行判断。这里我的方法是,先放置白皇后放好一种之后来进行黑皇后的放置,相同颜色的皇后不可以在同一对角线,行,列上面,黑白皇后在这上面的判断还是与上面的判断一致的,在这里我们放置黑皇后是只需要再进行一步该位置是否有白皇后的放置。
(这里0代表该位置没有被放置,1代表放置了白皇后,2代表放置黑皇后,这里同样是每个位置均可以被放置)
#include<iostream>
using namespace std;
int n;//皇后个数
int num[20][20]//棋盘大小
int sum=0;//方案个数
void init()//初始化棋盘
{
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
num[i][j]=0;
}
int Isdangerous(int row,int col)//白皇后位置放置判断
{
for(int i=0;i<row;i++)
{
if(num[i][col]==1)
{
return 0;
}
for(int j=0;j<n;j++)
{
if(num[i][j]==1)
{
if((i-j==row-col)||(col+row==i+j))
return 0;
}
}
}
return 1;
}
int Isdangerous2(int row,int col)//黑皇位置放置判断
{
for(int i=0;i<row;i++)
{
if(num[i][col]==2)
{
return 0;
}
for(int j=0;j<n;j++)
{
if(num[i][j]==2)
{
if((i-j==row-col)||(col+row==i+j))
return 0;
}
}
}
return 1;
}
void GetChess2(int dep)//DFS遍历棋盘放置黑皇后
{
if(dep==n)
{
sum++;
cout<<"第"<<sum<<"种"<<endl;
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
cout<<num[i][j]<<' ';
}
cout<<endl;
}
return ;
}
for(int i=0;i<n;i++)
{
if(num[dep][i]==1)//这里是判断该位置是否已经被白皇后放置了
{
continue;
}
if(Isdangerous2(dep,i)==1)
{
num[dep][i]=2;
GetChess2(dep+1);
num[dep][i]=0;
}
}
}
void GetChess(int ith)
{
if(ith==n)
{
GetChess2(0);//白皇后遍历完进行黑皇后的遍历放置
return ;
}
for(int i=0;i<n;i++)
{
if(Isdangerous(ith,i)==1)
{
num[ith][i]=1;
GetChess(ith+1);
num[ith][i]=0;
}
}
}
int main()
{
cin>>n;
init();
GetChess(0);
cout<<"一共有:"<<sum<<"种方案"<<endl;
return 0;
}
3、进阶版2n皇后(蓝桥杯版)
问题描述:给定一个n*n的棋盘,棋盘中有一些位置不能放皇后。现在要向棋盘中放入n个黑皇后和n个白皇后,使任意的两个黑皇后都不在同一行、同一列或同一条对角线上,任意的两个白皇后都不在同一行、同一列或同一条对角线上。问总共有多少种放法?n小于等于8。
输入格式: 输入的第一行为一个整数n,表示棋盘的大小。接下来n行,每行n个0或1的整数,如果一个整数为1,表示对应的位置可以放皇后,如果一个整数为0,表示对应的位置不可以放皇后。
输出格式:输出一个整数,表示总共有多少种放法。
问题解决:我们经过n皇后到2n皇后之后,我们可以很清楚知道,在这个2n皇后进阶版里面,存在着棋盘上有的位置是不可以放置棋子的,所以我们在这里只需要在2n皇后的基础上在进行一次当前位置是否可以进行棋子放置的判断即可。
(这里0表示不可以放置棋子、1可以放置棋子、2表示放置白色棋子、3表示放置黑色棋子)
#include<iostream>
using namespace std;
int n;//皇后个数
int num[20][20]//棋盘大小
int sum=0;//方法种类
int Isdangerous(int row,int col)//白皇后位置是否危险判断
{
if(num[row][col]==0)//是否可以放置棋子判断
{
return 0;
}
for(int i=0;i<row;i++)
{
if(num[i][col]==2)
{
return 0;
}
for(int j=0;j<n;j++)
{
if(num[i][j]==2)
{
if((i-j==row-col)||(col+row==i+j))
return 0;
}
}
}
return 1;
}
int Isdangerous2(int row,int col)//黑皇后位置是否危险判断
{
if(num[row][col]==0)
{
return 0;
}
for(int i=0;i<row;i++)
{
if(num[i][col]==3)
{
return 0;
}
for(int j=0;j<n;j++)
{
if(num[i][j]==3)
{
if((i-j==row-col)||(col+row==i+j))
return 0;
}
}
}
return 1;
}
void GetChess2(int dep)//DFS深度遍历棋盘放置黑皇后
{
if(dep==n)
{
sum++;
cout<<"第"<<sum<<"种"<<endl;
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
cout<<num[i][j]<<' ';
}
cout<<endl;
}
return ;
}
for(int i=0;i<n;i++)
{
if(num[dep][i]==2)
{
continue;
}
if(Isdangerous2(dep,i)==1)
{
num[dep][i]=3;
GetChess2(dep+1);
num[dep][i]=1;
}
}
}
void GetChess(int ith)//DFS深度遍历棋盘放置白皇后
{
if(ith==n)
{
GetChess2(0);
return ;
}
for(int i=0;i<n;i++)
{
if(Isdangerous(ith,i)==1)
{
num[ith][i]=2;
GetChess(ith+1);
num[ith][i]=1;
}
}
}
int main()
{
cin>>n;
for(int i=0;i<n;i++)//初始化棋盘
for(int j=0;j<n;j++)
{
cin>>num[i][j];
}
GetChess(0);
cout<<sum<<endl;
return 0;
}
第一次写CSDN博客如果有什么错误的地方希望各位大佬可以帮忙指出呀!