用c++。梵梵最近在玩 PVZ 泳池关卡,不考虑僵尸的移动以及植物的冷却时间,他想知道只运用樱桃炸弹(消耗阳光 150,樱桃炸弹可以消灭以它为中心周围 9 个格子内的僵尸)和荷叶(消耗阳光 25),在假设僵尸可以一次被樱桃炸弹消灭的情况下,消灭所有僵尸的最少阳光消耗量。 输入格式 输入 6 行 9 列数据,其中 1 表示有僵尸,0 表示无僵尸 输出格式 输出 1 个数据,表示消灭所有僵尸的最少阳光消耗量
时间: 2024-03-20 11:45:17 浏览: 64
好的,这是一个经典的搜索问题。我们可以使用深度优先搜索(DFS)来解决它。以下是C++代码实现:
```cpp
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 10;
int g[N][N]; // 存储地图
bool st[N][N]; // 标记数组,用于记录樱桃炸弹是否已经使用过
int ans = 0x3f3f3f3f; // 记录答案,初始值为正无穷
void dfs(int x, int y, int cnt, int suns) // (x,y)表示当前遍历到的坐标,cnt表示已经消灭的僵尸数量,suns表示已经使用的阳光数量
{
if (cnt == 0) // 如果已经消灭所有僵尸
{
ans = min(ans, suns); // 更新答案
return;
}
if (suns >= ans) return; // 剪枝:如果当前使用的阳光数量已经大于等于答案,就没有必要继续搜索了
if (y == 9) // 如果遍历到了最后一列,就从下一行开始遍历
{
x ++;
y = 0;
}
if (x == 6) return; // 如果已经遍历完整个地图,就返回
// 不使用樱桃炸弹的情况
dfs(x, y + 1, cnt, suns);
// 使用樱桃炸弹的情况
if (!st[x][y] && g[x][y])
{
st[x][y] = true; // 标记当前位置已经使用过樱桃炸弹
suns += 150;
cnt --;
for (int i = max(0, x - 1); i <= min(x + 1, 5); i ++) // 遍历以当前位置为中心的 3 * 3 的区域,将其中的僵尸全部消灭
for (int j = max(0, y - 1); j <= min(y + 1, 8); j ++)
if (g[i][j]) g[i][j] = 0, cnt --;
dfs(x, y + 1, cnt, suns);
cnt += 10;
suns -= 150;
for (int i = max(0, x - 1); i <= min(x + 1, 5); i ++) // 恢复地图
for (int j = max(0, y - 1); j <= min(y + 1, 8); j ++)
g[i][j] = 1;
st[x][y] = false; // 恢复标记数组
}
}
int main()
{
for (int i = 0; i < 6; i ++)
for (int j = 0; j < 9; j ++)
cin >> g[i][j];
int cnt = 0; // 统计僵尸数量
for (int i = 0; i < 6; i ++)
for (int j = 0; j < 9; j ++)
if (g[i][j]) cnt ++;
dfs(0, 0, cnt, 0);
cout << ans << endl;
return 0;
}
```
时间复杂度分析:每个格子都有两种状态(使用樱桃炸弹或不使用樱桃炸弹),因此总时间复杂度为 $O(2^{54})$,无法通过本题。但是由于实际上我们并不需要遍历所有状态,因此可以通过剪枝优化来减少搜索空间,从而通过本题。
阅读全文