Cuber QQ 现在有一个 n x m 的方形格子,每个格子有两种状态凸或者(如下图浅色表示,深色表示凸)。 现在用一个十字横截面的子弹(填充黑色部分) 去射击,被射中的小格子凹变凸,凸变凹。这种子弹最多可以覆盖 5 个格子,如图打完后,5 个格子凸状态发生了变化 请问最少需要几次射击使靶子中所有小格子都呈现凹的状态。 如果子弹中心点如果打到四个角上则只会影响 3 个格子,如果打到除四个角的边界上,则会影响到4 个格子。如下图黑色格子表示被子弹影响到的位置 输入格式 第一行两个用空格隔开的数字 n,m(1 < n,m < 17) ,表示方阵大小。 接下来 n 行描述小格子的状态,“X· 表示凸,“表示凹。c++
时间: 2024-04-17 13:23:24 浏览: 150
这个问题可以使用回溯法来解决。首先,我们需要定义一个函数来判断当前状态下还有多少个格子是凸的。然后,我们可以使用递归的方式,尝试对每个格子进行射击,并更新格子的状态。在每次射击后,我们可以判断是否所有格子都变成了凹的状态,如果是,则记录当前射击次数,并与之前的最小射击次数进行比较,更新最小次数。接着,我们回溯到上一次射击前的状态,继续尝试下一个格子的射击位置。最终,我们可以得到最少需要的射击次数。
以下是一个示例的 C++ 代码实现:
```cpp
#include <iostream>
#include <vector>
using namespace std;
int minShots = INT_MAX; // 最小射击次数
// 判断当前状态下还有多少个格子是凸的
int countConvex(vector<vector<char>>& grid) {
int count = 0;
for (const auto& row : grid) {
for (const char& cell : row) {
if (cell == 'X') {
count++;
}
}
}
return count;
}
// 射击函数
void shoot(vector<vector<char>>& grid, int row, int col, int shots) {
// 如果已经射击了超过最小次数,则剪枝
if (shots >= minShots) {
return;
}
// 射击当前位置
if (grid[row][col] == 'X') {
grid[row][col] = '.';
} else {
grid[row][col] = 'X';
}
// 判断是否所有格子都变成了凹的状态
if (countConvex(grid) == 0) {
minShots = min(minShots, shots);
} else {
// 尝试射击下一个位置
int n = grid.size();
int m = grid[0].size();
for (int i = row; i < n; i++) {
for (int j = (i == row ? col + 1 : 0); j < m; j++) {
if (i == row && j == col) {
continue; // 避免重复射击当前位置
}
if ((i == row || j == col) && (i == row + 1 || j == col + 1 || i == row - 1 || j == col - 1)) {
// 如果射击位置是四个角上的格子,则只会影响3个格子
continue;
}
shoot(grid, i, j, shots + 1);
// 回溯到上一次射击前的状态
if (grid[i][j] == 'X') {
grid[i][j] = '.';
} else {
grid[i][j] = 'X';
}
}
}
}
}
int main() {
int n, m;
cin >> n >> m;
vector<vector<char>> grid(n, vector<char>(m));
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
cin >> grid[i][j];
}
}
shoot(grid, 0, 0, 0);
cout << minShots << endl;
return 0;
}
```
这段代码使用回溯法来尝试每个格子的射击位置,并记录最小的射击次数。最后输出最少需要的射击次数。
希望能对你有所帮助!如果还有其他问题,请随时提问。
阅读全文