题目链接:http://acm.fzu.edu.cn/problem.php?pid=2150
分析
1.首先深搜求出图中共有几个连通块,超过2个就直接输出-1。
2.存储所有#的位置,枚举不同的#的起点,双起点广搜求出某个起点到达其他点的最长距离,找到其中最小的。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
#define INF 0x3f3f3f3f
int n,m;
char a[15][15];
int vis[15][15];
int dir[][2] = {{-1,0},{1,0},{0,-1},{0,1}};
struct Node {
int x,y,step;
Node(int x,int y,int step):x(x),y(y),step(step) {}
Node() {}
} node[15 * 15];
bool isValid(int x,int y)
{
return (x >= 0) && (x < n) && (y >= 0) && (y < m) && (a[x][y] == '#') && (!vis[x][y]);
}
void dfs(int x,int y)//求连通块的数量
{
vis[x][y] = 1;
for(int i = 0; i < 4; i++) {
int nx = x + dir[i][0];
int ny = y + dir[i][1];
if(isValid(nx,ny)) dfs(nx,ny);
}
}
int bfs(Node s,Node t)//双起点广搜
{
memset(vis,0,sizeof(vis));
int dis = 0;
queue<Node> q;
q.push(s);
q.push(t);
vis[s.x][s.y] = 1;
vis[t.x][t.y] = 1;
while(!q.empty()) {
Node head = q.front();q.pop();
for(int i = 0; i < 4; i++) {
int nx = head.x + dir[i][0];
int ny = head.y + dir[i][1];
if(isValid(nx,ny)) {
vis[nx][ny] = 1;
dis = max(dis,head.step + 1);
q.push(Node(nx,ny,head.step + 1));
}
}
}
//判断草是否全部烧完
for(int i = 0; i < n; i++)
for(int j = 0; j < m; j++)
if(a[i][j] == '#' && !vis[i][j]) return INF;
return dis;
}
int main()
{
int T;
scanf("%d",&T);
for(int k = 1; k <= T; k++) {
memset(vis,0,sizeof(vis));
scanf("%d%d",&n,&m);
int cnt = 0;
for(int i = 0; i < n; i++)
for(int j = 0; j < m; j++) {
scanf(" %c",&a[i][j]);
if(a[i][j] == '#') node[cnt].x = i,node[cnt].y = j,node[cnt++].step = 0;//存储所有草的位置
}
//判断连通块的个数
int num = 0;
for(int i = 0; i < n; i++)
for(int j = 0; j < m; j++)
if(isValid(i,j)) {
dfs(i,j);
num++;
}
printf("Case %d: ",k);
if(num > 2) printf("-1\n");
else {
int ans = INF;
//枚举不同的起点,可以同时适应只有一个连通块或两个连通块的情况
for(int i = 0; i < cnt; i++)
for(int j = i; j < cnt; j++)
ans = min(ans,bfs(node[i],node[j]));
printf("%d\n",ans);
}
}
return 0;
}