题目链接:UVa 11214
题目描述:
给定一个 n × m n\times m n×m的棋盘,棋盘中的某些点是被标记的,你需要防止最少的皇后,让皇后覆盖这些点或者攻击这些点,输出最少的皇后数量。
注意:一个皇后的攻击范围为其所在行和列以及两条对角线。
题解:
本题我们可以使用迭代加深搜来求解,我们只需要依次枚举放置皇后的数量,然后使用 D F S DFS DFS放置皇后,到最终时候判断棋盘中的点时候全部被覆盖即可。我们需要用四个数组来表示覆盖情况,这四个数组分别表示:某一行是否被覆盖,某一列是否被覆盖,某条主对角线是否被覆盖,某条副对角线是否被覆盖。容易发现的是:同一条主对角线上的点的横纵坐标之差相等,而同一条副对角线上的横纵坐标之和相等,所以我们就可以通过横纵坐标的和与差来判断改点属于的对角线。
代码:
#include <bits/stdc++.h>
const int MAXN = 10;
using namespace std;
int caseID, maxDepth, n, m;
string board[MAXN];
bool vis[4][MAXN * 2];
bool cover()
{
for (int i = 0; i < n; i++) {
if (vis[0][i]) { continue; }
for (int j = 0; j < m; j++) {
if (board[i][j] != 'X') { continue; }
if (vis[1][j] || vis[2][i + j] || vis[3][i - j + MAXN]) { continue; }
return false;
}
}
return true;
}
bool dfs(int nowDepth, int nowRow)
{
if (nowDepth == maxDepth) {
return cover();
}
if (n - nowRow < maxDepth - nowDepth) { return false; }
int temp[4] = {0};
for (int j = 0; j < m; j++) { // 选择放置位置
temp[0] = vis[0][nowRow];
temp[1] = vis[1][j];
temp[2] = vis[2][nowRow + j];
temp[3] = vis[3][nowRow - j + MAXN];
vis[0][nowRow] = true;
vis[1][j] = true;
vis[2][nowRow + j] = true;
vis[3][nowRow - j + MAXN] = true;
if (dfs(nowDepth + 1, nowRow + 1)) { return true; };
vis[0][nowRow] = temp[0];
vis[1][j] = temp[1];
vis[2][nowRow + j] = temp[2];
vis[3][nowRow - j + MAXN] = temp[3];
}
if (dfs(nowDepth, nowRow + 1)) { return true; } // 当前这一行不放
return false;
}
bool getInput()
{
cin >> n;
if (n == 0) { return false; }
cin >> m;
for (int i = 0; i < n; i++) {
cin >> board[i];
}
return true;
}
int main()
{
while (getInput()) {
memset(vis, 0, sizeof(vis));
for (maxDepth = 0; ; maxDepth++) {
if (dfs(0, 0)) {
caseID++;
cout << "Case " << caseID << ": " << maxDepth << endl;
break;
}
}
}
return 0;
}