一、内容

题意:选择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;
}