作者 : Xia Xinyu
日期 : -1-3
原题链接
听说最近两斑点的奶牛最受欢迎,约翰立即购进了一批两斑点牛。
不幸的是,时尚潮流往往变化很快,当前最受欢迎的牛变成了一斑点牛。
约翰希望通过给每头奶牛涂色,使得它们身上的两个斑点能够合为一个斑点,让它们能够更加时尚。
牛皮可用一个 N×M 的字符矩阵来表示,如下所示:
…
…XXXX…XXX…
…XXXX…XX…
.XXXX…XXX…
…XXXXX…
…XXX…
其中,X 表示斑点部分。
如果两个 X 在垂直或水平方向上相邻(对角相邻不算在内),则它们属于同一个斑点,由此看出上图中恰好有两个斑点。
约翰牛群里所有的牛都有两个斑点。
约翰希望通过使用油漆给奶牛尽可能少的区域内涂色,将两个斑点合为一个。
在上面的例子中,他只需要给三个 . 区域内涂色即可(新涂色区域用 ∗ 表示):
…
…XXXX…XXX…
…XXXX*…XX…
.XXXX…**…XXX…
…XXXXX…
…XXX…
请帮助约翰确定,为了使两个斑点合为一个,他需要涂色区域的最少数量。
输入格式
第一行包含两个整数 N 和 M。
接下来 N 行,每行包含一个长度为 M 的由 X 和 . 构成的字符串,用来表示描述牛皮图案的字符矩阵。
输出格式
输出需要涂色区域的最少数量。
数据范围
1≤N,M≤50
输入样例:
6 16
…
…XXXX…XXX…
…XXXX…XX…
.XXXX…XXX…
…XXXXX…
…XXX…
输出样例:
3
思路:推导出最优解一定可以用曼哈顿距离公式求出(反证法)
import java.util.*;class Main{static int[] dx = {1,0,-1,0}; //下右上左static int[] dy = {0,1,0,-1};static char[][] g = new char[60][60];static int n,m;public static void dfs(int x,int y,List<Pair> l){g[x][y] = '.';for(int i = 0; i < 4; i ++){int aa = x + dx[i],bb = y + dy[i];if(aa >= 0 && aa < n && bb >= 0 && bb < m && g[aa][bb] == 'X'){l.add(new Pair(aa,bb));dfs(aa,bb,l);}}}public static void main(String[] args){Scanner in = new Scanner(System.in);n = in.nextInt();m = in.nextInt();for(int i = 0; i < n; i ++){g[i] = in.next().toCharArray();}List<Pair> a = new ArrayList<>();List<Pair> b = new ArrayList<>();boolean flag = false;//搜第一个连通块for(int i = 0; i < n; i ++){for(int j = 0; j < m; j ++){if(g[i][j] == 'X'){a.add(new Pair(i,j));dfs(i,j,a);flag = true;break;}}if(flag)break;}//搜第二个连通块for(int i = 0; i < n; i ++){for(int j = 0; j < m; j ++){if(g[i][j] == 'X'){b.add(new Pair(i,j));dfs(i,j,b);}}}// System.out.println(a.size());// System.out.println(b.size());int res = (int)2e9;for(Pair x : a){for(Pair y : b){res = Math.min(res,Math.abs(x.x - y.x) + Math.abs(x.y - y.y));}}System.out.println(res - 1);}}class Pair {int x;int y;public Pair(int x,int y){this.x = x;this.y = y;}}