一、内容
题意:选择2个起点(#)代表着火点,每个着火点会向上下左右四个方向蔓延,一秒蔓延一次,问最少多少秒所有的#都能被点燃。
二、思路
- 暴力枚举所有情况,即2个起点所在坐标。然后将2个起点加入队列,每秒钟将队列里面所有点拿出来蔓延一次,最后到所有的**#的点燃结束**。
三、代码
#include <cstdio>
#include <cstring>
#include <queue>
#include <iostream>
using namespace std;
const int N = 10;
int vis[N][N], t, n, m, sx[100], sy[100], cnt, num, ans, temNum;
char g[N][N], tem[N][N];
int dx[4] = {1, 0, 0, -1};
int dy[4] = {0, 1, -1, 0};
struct node{
int x, y;
node(int x, int y): x(x), y(y){}
};
bool ok(int x, int y) {
if(x < 0 || y < 0 || x >= n || y >= m || tem[x][y] == '.' || vis[x][y]) return false;
return true;
}
void bfs(int sx1, int sy1, int sx2, int sy2) {
queue<node> q;
memcpy(tem, g, sizeof g);
memset(vis, 0, sizeof vis);
int step = 0;
q.push(node(sx1, sy1));
q.push(node(sx2, sy2));
vis[sx1][sy1] = 1;
vis[sx2][sy2] = 1;
tem[sx1][sy1] = '.';
tem[sx2][sy2] = '.';
while (q.size()) {
step++;
if (step >= ans) return;//小小的剪枝
// 将上一秒的全部出队 j = q.size()
for (int i = 0, j = q.size(); i < j; i++) {
node t = q.front();
q.pop();
for (int k = 0; k < 4; k++) {
int fx = t.x + dx[k];
int fy = t.y + dy[k];
if (ok(fx, fy)) {
vis[fx][fy] = 1;
tem[fx][fy] = '.';
q.push(node(fx, fy));
temNum--;
if (temNum == 0) {
ans = step;
}
}
}
}
}
}
int main() {
scanf("%d", &t);
for (int ci = 1; ci <= t; ci++) {
scanf("%d%d", &n, &m);
for (int i = 0; i < n; i++) {
scanf("%s", g[i]);
}
cnt = 0; num = 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (g[i][j] == '#') {
//记录一下#的位置
sx[cnt] = i;
sy[cnt++] = j;
num++; //记录个数
}
}
}
//遍历所有的情况
ans = 1000;
num -= 2;
if (num > 0) {
//暴力枚举2个起点所在位置
for (int i = 0; i < cnt; i++) {
for (int j = i + 1; j < cnt; j++) {
temNum = num;
bfs(sx[i], sy[i], sx[j], sy[j]);
}
}
printf("Case %d: %d\n", ci, ans == 1000 ? -1 : ans);
} else {
printf("Case %d: 0\n", ci);
}
}
return 0;
}