来一道遍历枚举的题目做做吧。
题目
ZCMU-1803
1803: 2n皇后问题
Time Limit: 1 Sec Memory Limit: 128 MB
Submit: 46 Solved: 37
[Submit][Status][Web Board]
Description
给定一个n*n的棋盘,棋盘中有一些位置不能放皇后。现在要向棋盘中放入n个黑皇后和n个白皇后,使任意的两个黑皇后都不在同一行、同一列或同一条对角线上,任意的两个白皇后都不在同一行、同一列或同一条对角线上。问总共有多少种放法?n小于等于8。
Input
输入的第一行为一个整数n,表示棋盘的大小。接下来n行,每行n个0或1的整数,如果一个整数为1,表示对应的位置可以放皇后,如果一个整数为0,表示对应的位置不可以放皇后。
Output
输出一个整数,表示总共有多少种放法。
Sample Input
4
1 1 1 1
1 1 1 1
1 1 1 1
1 1 1 1
4
1 0 1 1
1 1 1 1
1 1 1 1
1 1 1 1
Sample Output
2
0
想法
这道题你一乍看可能黑皇后白皇后都在动,实际上结合一下初中动点的核心:用不动应万动,我们把白皇后的位子确定了,就可以确定黑皇后的位子,这样跑bfs遍历就完事了
所以其实就是建树,根据白子能不能放跑到n个放满,然后跑黑子情况,跑到n个放满,最后弹出,ans++
模块解释
1.check当前位置是否可以放棋子
int check(int temp[10][10],int x,int y)
{
//同行同列检测
for(int i=1;i<n;++i)
{
if(temp[i][y])return 0;
if(temp[x][i])return 0;
}
//对角线检查 右下
for(int i=x,j=y;i<=n&&j<=n;i++,j++)
if(temp[i][y])return 0;
//对角线检查 左上
for(int i=x,j=y;i>0&&j>0;i--,j--)
if(temp[i][j])return 0;
//对角线检查 右上
for(int i=x,j=y;i>0&&j<=n;i--,j++)
if(temp[i][j])return 0;
//对角线检查,左下
for(int i=x,j=y;i<=n&&j>0;i++,j--)
if(temp[i][j])return 0;
//说明这个地方可以放
return 1;
}
2.遍历搜索的过程
void find_blackqueen(int x,int cnt)
{
if(x>n)
{
if(cnt==n)ans++;
return;
}
for(int i=1;i<=n;++i)
{
if(check(black_queen, x, i)&&!white_queen[x][i]&&mp[x][i])
{
black_queen[x][i] = 1;
find_blackqueen(x+1, cnt+1);
black_queen[x][i] = 0;
}
}
}
//bfs寻找遍历
void find_whitequeen(int x,int cnt)
{
if(x>n)
{
if(cnt==n)find_blackqueen(1,0);
return;
}
for(int i=1;i<=n;++i)
{
if(check(white_queen, x, i)==1&&mp[x][i]==1)
{
white_queen[x][i] = 1;
find_whitequeen(x+1, cnt+1);
white_queen[x][i] = 0;
}
}
}
3.主函数
int main()
{
while(~scanf("%d",&n))
{
//初始化
ans = 0;
m(black_queen);
m(white_queen);
rep(i, 1, n)
rep(j, 1, n)
scanf("%d",&mp[i][j]);
//启动
find_whitequeen(1, 0);
printf("%d\n",ans);
}
return 0;
}
AC代码
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define pre(i,a,b) for(int i=a;i>=b;--i)
#define m(x) memset(x,0,sizeof x)
typedef long long ll;
const int maxn = 10;
//全局变量定义
int n,mp[maxn][maxn],cnt,ans;
int black_queen[maxn][maxn];
int white_queen[maxn][maxn];
int check(int temp[10][10],int x,int y)
{
//同行同列检测
for(int i=1;i<n;++i)
{
if(temp[i][y])return 0;
if(temp[x][i])return 0;
}
//对角线检查 右下
for(int i=x,j=y;i<=n&&j<=n;i++,j++)
if(temp[i][y])return 0;
//对角线检查 左上
for(int i=x,j=y;i>0&&j>0;i--,j--)
if(temp[i][j])return 0;
//对角线检查 右上
for(int i=x,j=y;i>0&&j<=n;i--,j++)
if(temp[i][j])return 0;
//对角线检查,左下
for(int i=x,j=y;i<=n&&j>0;i++,j--)
if(temp[i][j])return 0;
//说明这个地方可以放
return 1;
}
void find_blackqueen(int x,int cnt)
{
if(x>n)
{
if(cnt==n)ans++;
return;
}
for(int i=1;i<=n;++i)
{
if(check(black_queen, x, i)&&!white_queen[x][i]&&mp[x][i])
{
black_queen[x][i] = 1;
find_blackqueen(x+1, cnt+1);
black_queen[x][i] = 0;
}
}
}
//bfs寻找遍历
void find_whitequeen(int x,int cnt)
{
if(x>n)
{
if(cnt==n)find_blackqueen(1,0);
return;
}
for(int i=1;i<=n;++i)
{
if(check(white_queen, x, i)==1&&mp[x][i]==1)
{
white_queen[x][i] = 1;
find_whitequeen(x+1, cnt+1);
white_queen[x][i] = 0;
}
}
}
int main()
{
while(~scanf("%d",&n))
{
//初始化
ans = 0;
m(black_queen);
m(white_queen);
rep(i, 1, n)
rep(j, 1, n)
scanf("%d",&mp[i][j]);
//启动
find_whitequeen(1, 0);
printf("%d\n",ans);
}
return 0;
}