问题描述 给定一个n*n的棋盘,棋盘中有一些位置不能放皇后。现在要向棋盘中放入n个黑皇后和n个白皇后,使任意的两个黑皇后都不在同一行、同一列或同一条对角线上,任意的两个白皇后都不在同一行、同一列或同一条对角线上。问总共有多少种放法?n小于等于8。输入格式 输入的第一行为一个整数n,表示棋盘的大小。
接下来n行,每行n个0或1的整数,如果一个整数为1,表示对应的位置可以放皇后,如果一个整数为0,表示对应的位置不可以放皇后。输出格式 输出一个整数,表示总共有多少种放法。样例输入4
1 1 1 1
1 1 1 1
1 1 1 1
1 1 1 1样例输出2样例输入4
1 0 1 1
1 1 1 1
1 1 1 1
1 1 1 1样例输出0/*
1,每一行都必须放一个黑皇后、一个白皇后。
2,从第一行到最后一行,先把黑皇后放好,再放白皇后。(当然不只这种放法)
3,放的时候注意的是0的地方不能放,放过的地方不能放。
(本以为是在N皇后基础上直接是有序选两个的总和,并不是:不同放法可能有相同的使用点)
*/
#include<iostream>
using namespace std;
int s[13][13];
int n;
int count=0;
void dfs(int i,int q)//dfs为按行处理,从上往下一行一行进行
{
for(int j=0;j<n;j++)
{
//不能放的或者已经放过的
if(s[i][j]==0||s[i][j]==2)
{
continue;
}
int flag=1;//默认可以放
int y1=j-1;
int y2=j+1;//y1 y2分别表示左上角和右上角
for(int l=i-1;l>=0;l--)
{
//判断同一列、斜线上是否有相同皇后(同行肯定不会有:从上到下进行的)
//同一列
if(s[l][j]==q)
{
flag=0;
break;
}
//斜线
if(y1>=0&&s[l][y1]==q)//y1左上角
{
flag=0;
break;
}
y1--; //下一行的左上角
if(y2<n&&s[l][y2]==q)//y2右上角
{
flag=0;
break;
}
y2++;//下下行的右上角
}
//以上的都是判断
if(flag)
{
s[i][j]=q;//放皇后
if(i<n-1)
{
dfs(i+1,q);//i = 2;i+1 = 3是黑的最后一次
}
else
{
//黑皇后放完了,开始放白皇后;
//白皇后放完的话就是一种方法结束
if(q==2)
{
dfs(0,3);
}
else
{
count++;
}
}
s[i][j]=1;//复原开始下一次,复原很重要
}
}
}
int main()
{
cin>>n;
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
cin>>s[i][j];
}
}
dfs(0,2);//黑皇后
cout<<count<<endl;
return 0;
}以上代码来自:https://www.cnblogs.com/xiangguoguo/p/5478200.html
以下是自己写的仿写的代码
#include<iostream>
using namespace std;
#define MAX 10
int map[10][10];
int num;
int res = 0;
void solve(int line,int color)
{
int i,flag,j;
int lu,ru;//左上角和右上角
for(i = 0; i < num; i++)
{
flag = 1;//要放进来,否则问题很大,在以后做题的时候要注意flag的位置
if(map[line][i] == 0||map[line][i] == 2)
{
continue;
}
//接下来是判断条件
lu = i - 1;
ru = i + 1;
for(j = line-1; j >= 0; j--)
{
//判断同列的情况
if(map[j][i] == color)
{
flag = 0;
break;
}
//判断对角线,左对角
if(lu >= 0 && map[j][lu] == color)
{
flag = 0;
break;
}
lu--;
//判断对角线,右对角
if(ru < num && map[j][ru] == color)
{
flag = 0;
break;
}
ru++;
}
if(flag)
{
map[line][i] = color;
if(line < num - 1)
{
solve(line+1, color);//2表示黑皇后
}
else
{
if(color == 2)
{
solve(0,3);
}
else
{
res ++ ;
}
}
map[line][i] = 1;
}
}
}
int main()
{
int i,j;
cin >> num;
for(i = 0; i < num; i++)
{
for(j = 0; j < num; j++)
{
cin >> map[i][j];
}
}
solve(0,2);
cout << res;
system("pause");
return 0;
}总结:这类的问题类似于走迷宫的问题,用到了回溯法。
1.要搞清楚如何按顺序一步步地试探递归
2.要搞清楚条件的判断
3.综合1 2 找到里边重复的机制,形成递归
4.该解题方法好的地方在于用一个color区分黑白,使程序不用黑白分别用两个函数处理,然后按行的顺序一层
层的进行试探,使得解题思路以及处理会清晰很多
773

被折叠的 条评论
为什么被折叠?



