题解
两个熊孩子可以选择2个地点进行点火,分三种情况讨论,1个联通块,2个联通块,2个以上联通块。
2个以上联通块肯定就没办法烧完了直接-1。
2个联通块时由于数据量很小,对于每个联通块,枚举点火点BFS得到当前联通块所有点都着火的所需时间,每个联通块不同点火点的时间取最小,两个联通块的时间取最大。
1个联通块时,由于数据很小,先将当前联通块以每个位置为点火点,引燃每个位置的所需时间求出来。
枚举两个点火点作为当前方案,对于每个位置当前点燃时间则为两个点火点引燃当前位置的较小值,然后每个位置取最大则为当前方案所需时间,每个方案取最小即为答案。
AC代码
#include <stdio.h>
#include <queue>
#include <vector>
#include <iostream>
#include <algorithm>
#define fst first
#define sed second
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int N = 20;
int dir[4][2] = { -1, 0, 1, 0, 0, -1, 0, 1 };
char g[N][N];
bool vis[N][N];
int f[N][N][N][N]; //f[i][j][x][y]以ij为起点到达xy的时间
int n, m, blk;
vector<pair<int, int> > vec[110];
struct node
{
int x, y, k;
node(int a, int b, int c) : x(a), y(b), k(c) {}
};
void DFS(int x, int y)
{
vec[blk].push_back(make_pair(x, y)); //每个联通块的点存入vec
vis[x][y] = 1;
for (int i = 0; i < 4; ++i)
{
int xx = x + dir[i][0], yy = y + dir[i][1];
if (xx >= 1 && xx <= n && yy >= 1 && yy <= m && g[xx][yy] == '#' && !vis[xx][yy])
DFS(xx, yy);
}
}
void BFS(int p[N][N], int xx, int yy)
{
memset(vis, 0, sizeof(vis));
queue<node> q;
q.push(node(xx, yy, 0));
vis[xx][yy] = 1;
p[xx][yy] = 0;
while (!q.empty())
{
int x = q.front().x, y = q.front().y, k = q.front().k + 1; q.pop();
for (int i = 0; i < 4; ++i)
{
xx = x + dir[i][0], yy = y + dir[i][1];
if (xx >= 1 && xx <= n && yy >= 1 && yy <= m && g[xx][yy] == '#' && !vis[xx][yy])
q.push(node(xx, yy, k)), vis[xx][yy] = 1, p[xx][yy] = k;
}
}
}
int main()
{
#ifdef LOCAL
freopen("C:/input.txt", "r", stdin);
#endif
int T;
cin >> T;
for (int ti = 1; ti <= T; ti++)
{
printf("Case %d: ", ti);
for (int i = 0; i < 110; ++i)
vec[i].clear();
memset(f, 0x3f, sizeof(f));
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; ++i)
scanf("%s", g[i] + 1);
blk = 0; //联通块
memset(vis, 0, sizeof(vis));
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j)
if (g[i][j] == '#' && !vis[i][j])
DFS(i, j), ++blk;
//cout << blk << endl;
int ans = 0;
if (blk > 2)
ans = -1;
else if (blk == 2)
{
for (int b = 0; b < 2; ++b) //两个联通块
{
int mi = INF;
for (int i = 0; i < vec[b].size(); ++i)
{
int x = vec[b][i].fst, y = vec[b][i].sed;
BFS(f[x][y], x, y); //得到以xy为起点到达其它点最短路
int mx = 0;
for (int j = 0; j < vec[b].size(); ++j)
{
int xx = vec[b][j].fst, yy = vec[b][j].sed; //其它所有点
mx = max(mx, f[x][y][xx][yy]); //所有点取max
}
mi = min(mi, mx); //所有选择点取min
}
ans = max(ans, mi); //两个分块取max
}
}
else //单联通块
{
for (int i = 0; i < vec[0].size(); ++i)
{
int x = vec[0][i].fst, y = vec[0][i].sed;
BFS(f[x][y], x, y); //求每个点为起点到达其他点最短路
}
ans = INF;
for (int a = 0; a < vec[0].size(); ++a)
{
int ax = vec[0][a].fst, ay = vec[0][a].sed;
for (int b = a; b < vec[0].size(); ++b)
{
int bx = vec[0][b].fst, by = vec[0][b].sed; //选两个点
int mx = 0;
for (int i = 0; i < vec[0].size(); ++i)
{
int xx = vec[0][i].fst, yy = vec[0][i].sed; //其它所有点
mx = max(mx, min(f[ax][ay][xx][yy], f[bx][by][xx][yy])); //ab取min 所有点取max
}
ans = min(ans, mx); //所有选择点取min
}
}
}
printf("%d\n", ans);
}
return 0;
}