Description

在一个 N 行 M 列的字符网格上, 恰好有 2 个彼此分开的连通块。每个连通 块的一个格点与它的上、下、左、右的格子连通。如下图所示: 

现在要把这 2 个连通块连通, 求最少需要把几个’.’转变成’X’。上图的例子中, 最少只需要把 3个’.’转变成’X’。下图用’*’表示转化为’X’的格点。 

Input 

第 1 行:2 个整数 N 和 M(1<=N,M<=50) 接下来 N 行,每行 M 个字符, ’X’表示属于某个连通块的格点,’.’表示不属于某 个连通块的格点

Output 

第 1 行:1 个整数,表示最少需要把几个’.’转变成’X’

Sample Input 

6 16
................
..XXXX....XXX...
...XXXX....XX...
.XXXX......XXX..
........XXXXX...
.........XXX....

Sample Output 

3

Hint

1<=N,M<=50

 

       这道题有两种做法,一种是先用dfs去区分两个连通块,然后再用bfs去跑两个连通块相连的最小值;另一种方法是运用了曼哈顿的思想,我们先用dfs去把每个连通块的坐标存起来,然后去遍历两个连通块的坐标的最小曼哈顿距离就好了。

       不得不说第二种方法角度刁钻思路惊奇...


Code:

#include <bits/stdc++.h>
#define maxn 55
#define inf 0x3f3f3f3f
using namespace std;
char pre[maxn][maxn];
struct Node{
	int x,y;
}Edge;
vector<Node> v[2];
int dir[4][2] = {1,0,0,1,-1,0,0,-1};
int n,m,s;

bool Check(int x,int y){
	if(x >= 0 && y >= 0 && x < n && y < m && pre[x][y] == 'X')return true;
	return false;
}

void dfs(int x,int y){
	pre[x][y] = '.';
	Edge.x = x;
	Edge.y = y;
	v[s].push_back(Edge);
	for(int i=0;i<4;i++){
		int xx = x + dir[i][0];
		int yy = y + dir[i][1];
		if(Check(xx, yy)){
			dfs(xx, yy);
		}
	}
}

int main()
{
	scanf("%d%d",&n,&m);
	for(int i=0;i<n;i++){
		scanf("%s",pre[i]);
	}
	s = 0;
	for(int i=0;i<n;i++){
		for(int j=0;j<m;j++){
			if(pre[i][j] == 'X'){
				dfs(i,j);
				s ++;
			}
		}
	}
	int ans = inf;
	for(int i=0;i<v[0].size();i++){
		for(int j=0;j<v[1].size();j++){
			ans = min(ans, abs(v[0][i].x - v[1][j].x) + abs(v[0][i].y - v[1][j].y) - 1);
		}
	}
	printf("%d\n",ans);
	return 0;
}