问题描述
地球人都知道,在国际象棋中,后如同太阳,光芒四射,威风八面,它能控制横、坚、斜线位置。
看过清宫戏的中国人都知道,后宫乃步步惊心的险恶之地。各皇后都有自己的势力范围,但也总能找到相安无事的办法。
所有中国人都知道,皇权神圣,伴君如伴虎,触龙颜者死......
现在有一个n*n的皇宫,国王占据他所在位置及周围的共9个格子,这些格子皇后不能使用(如果国王在王宫的边上,占用的格子可能不到9个)。当然,皇后也不会攻击国王。
现在知道了国王的位置(x,y)(国王位于第x行第y列,x,y的起始行和列为1),请问,有多少种方案放置n个皇后,使她们不能互相攻击。
看过清宫戏的中国人都知道,后宫乃步步惊心的险恶之地。各皇后都有自己的势力范围,但也总能找到相安无事的办法。
所有中国人都知道,皇权神圣,伴君如伴虎,触龙颜者死......
现在有一个n*n的皇宫,国王占据他所在位置及周围的共9个格子,这些格子皇后不能使用(如果国王在王宫的边上,占用的格子可能不到9个)。当然,皇后也不会攻击国王。
现在知道了国王的位置(x,y)(国王位于第x行第y列,x,y的起始行和列为1),请问,有多少种方案放置n个皇后,使她们不能互相攻击。
输入格式
一行,三个整数,皇宫的规模及表示国王的位置
输出格式
一个整数,表示放置n个皇后的方案数
样例输入
8 2 2
样例输出
10
数据规模和约定
n<=12
思路:这是一道非常经典的n皇后问题 回想起三个月前被这道题支配的恐惧...
当时理解的根本不算透彻,这次要争取把之前给留下的坑补上
法1:
因为已知同一行或者同一列 只能放一个皇后,我们可以从行开始看 枚举每一行开始搜
判断这一行中的格子的列、对角线、副对角线是否可以放,类似全排列问题 复杂度O(n!)
关于对角线: 这里我们dfs时u为行,对应坐标系中的x
在dfs中枚举每一列i,这里的i对应坐标系中的y
正对角线(dg),在数学中可以等价于y=x+b,即 b=y-x; (这里为什么把截距b提出来,因为正是b来表示y与x的关系,即表示对角线关系)
副对角线(udg),同理可以化为y=-x+b,即b=y+x;
注意,由于正对角线由y-x表示的b 对于n行n列的图来说,会有负数 这里我们将b=y-x+n即可
画个图方便理解一下
#include <iostream> #include <cstdio> #include <algorithm> #include <stack> #include <cstring> #include <iomanip> #include <cmath> using namespace std; const int N = 25; int n, ans; bool g[N][N]; int col[N], dg[N], udg[N]; // 分别表示每列、正对角线、副对角线 void init(int a, int b) // 预处理国王对应的9个坐标 { for (int i = -1; i <= 1; i ++ ) for (int j = -1; j <= 1; j ++ ) g[a + i][b + j] = true; } void dfs(int u) // 搜索到第u行 { if (u == n + 1) { ans ++ ; return ; } for (int i = 1; i <= n; i ++ ) // 枚举每一列是否选取 { if (!col[i] && !dg[i - u + n] && !udg[u + i] && !g[u][i]) // 如果u行i列可以放的话 { g[u][i] = col[i] = dg[i - u + n] = udg[u + i] = true; dfs(u + 1); // 搜下一行 g[u][i] = col[i] = dg[i - u + n] = udg[u + i] = false; // 恢复现场 } } } int main() { int a, b; cin >> n >> a >> b; init(a, b); dfs(1); // 从第一行开始搜索 cout << ans << endl; return 0; }
法2:原始的搜索方法 选或者不选
这种方法是将棋盘每个格子遍历一遍 分别计算选和不选
但这种方法复杂度为O(2的n^2) 样例 大概n=10以上就跑不动了 所以了解一下 明白原始的思路即可
#include <iostream> #include <cstdio> #include <algorithm> #include <stack> #include <cstring> #include <iomanip> #include <cmath> using namespace std; const int N = 25; int n, ans; bool g[N][N]; int row[N], col[N], dg[N], udg[N]; // 分别表示每行、每列、正对角线、副对角线 void init(int a, int b) // 预处理国王对应的9个坐标 { for (int i = -1; i <= 1; i ++ ) for (int j = -1; j <= 1; j ++ ) g[a + i][b + j] = true; } void dfs(int x, int y, int s) { if (y == n + 1) y = 1, x ++ ; if (x == n + 1) { if (s == n) ans ++ ; return ; } // 不放皇后 dfs(x, y + 1, s); // 放皇后 if (!row[x] && !col[y] && !dg[y - x + n] && !udg[x + y] && !g[x][y]) { row[x] = col[y] = dg[y - x + n] = udg[x + y] = g[x][y] = true; dfs(x, y + 1, s + 1); row[x] = col[y] = dg[y - x + n] = udg[x + y] = g[x][y] = false; } } int main() { int a, b; cin >> n >> a >> b; init(a, b); dfs(1, 1, 0); // 从第一行第一列开始搜索 cout << ans << endl; return 0; }