题目:
八皇后问题 - 计蒜客 381 - Virtual Judge (vjudge.net)
八皇后问题 - 题库 - 计蒜客 (jisuanke.com)
题面:
分析:
八皇后问题的小变形
在8x8的矩阵中找到数字之和最大的八个位置,同时每个位置上两个对角线和一列中只有一个旗子
依然是全部深搜遍历所有可能性,找到最大的那一种
如何判断当前位置能不能放呢?
一列很好判断,定义一个列 数组 保存那一列中有棋子就行
至于对角线,我们需要找到用于标识每个点对角线之间区别的特点
先以由左下往右上的对角线为例,画画可以很明显发现,每个对角线之间都是平行的
也就是说,他们的斜率不需要考虑,只需要考虑偏移量
根据直线的点斜式方程
我们是不需要考虑的,默认为 1 就行,所以每一对
都有一个确定的
如果两组 带入方程后所得的
相同,那么他们肯定在一条斜线上
那么怎么用计算机语言实现呢?
用数组存储每一个 对应的
,由
可知 dg[x - y] = b
对于另一条对角线,只需要把 x - y 变成 x + y 即可,因为斜率相乘为 -1 的两条直线相互垂直
接下来就很好办了,遍历每一层即可
注意 x - y 会成为负数,加个偏移量 dg[(x - y + N) % N] 就行
或者像我这样把数组开大一点然后只加个 8 就行
代码:
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 20;
bool dg[N], udg[N], cnt[N]; // 两个对角线跟列线
int k, res;
int g[N][N];
void dfs(int u, int num) // u 代表层数, num 代表数字之和
{
if (u == 9) // 当u = 8的那一层选完之后就结束
{
res = max(num, res);
return;
}
for (int i = 1; i <= 8; i++)
{
if ( !dg[u + i] && !udg[8 + i - u] && !cnt[i]) // 如果两个对角线和当前列上都没有放过则可以放
{
dg[u + i] = udg[8 + i - u] = cnt[i] = true;
dfs(u + 1, num + g[u][i]);
dg[u + i] = udg[8 + i - u] = cnt[i] = false;
}
}
}
int main()
{
ios::sync_with_stdio(false); cin.tie(0);
cin >> k;
while (k--)
{
memset(udg, false, sizeof udg); // 初始化
memset(dg, false, sizeof dg);
memset(cnt, false, sizeof cnt);
res = 0;
for (int i = 1; i <= 8; i++) // 读入数据
for (int j = 1; j <= 8; j++)
cin >> g[i][j];
dfs(1,0); // 开搜
cout << res << "\n";
}
return 0;
}