题目来源:
HihoCoder1310
题目要求:
给你一张某一海域卫星照片,你需要统计:1. 照片中海岛的数目
2. 照片中面积不同的海岛数目
3. 照片中形状不同的海盗数目
其中海域的照片如下,"."表示海洋,"#"表示陆地。在"上下左右"四个方向上连在一起的一片陆地组成一座岛屿。
.####.......#.####.#......#...##.#.
上图所示的照片中一共有4座岛屿;其中3座面积为4,一座面积为2,所以不同面积的岛屿数目是2;有两座形状都是"####",所以形状不同的岛屿数目为3。
解答:
本题使用搜索算法就可以很容易地找到所有的岛屿。利用深度或者广度优先搜索找到每一个连续的由“#”包含的区域,同时统计每个连续区域中“#”的个数就可以得到每一个岛屿的面积。因此,题目中要求的岛屿数、面积不同的岛屿数可以直接通过搜索求得。本题的重点在于如何记录岛屿的形状,从而求得形状不同的岛屿数目。这里笔者设定了一种方式,将岛屿的形状特征转换为一个字符串。具体格式为:<width>,<height>:<map>。首先,我们用一个恰好可以容纳当前岛屿的矩形区域来将岛屿包围,width和height就是该矩形的宽度和高度,<map>则是当前岛屿在该岛屿的最小矩形部分的地图数据,逐行数据连接为一个字符串。具体转换方式如下图样例:
到这里,本题的主要解答思路可以总结为:首先通过搜索找到所有的岛屿,然后将这些岛屿进行排序,排序标准为:首先按照岛屿面积升序排列,当两个岛屿的面积相同时,按照形状特征字符串的字典序排序,显然,如果两个岛屿的面积不同,那么其形状也一定不同。
排序完成后,就可以很容易地得到岛屿数目、不同面积的岛屿数目、不同形状的岛屿数目这些数据的情况了。
输入输出格式:
输入:第一行包含两个人整数:N 和 M,(1 ≤ N,M ≤ 50),表示照片的行数和列数。
以下一个 N * M 的矩阵,表示表示海域的照片。
输出:
输出一个整数,表示最少的机器数目。
程序代码:
package hihocoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Scanner;
/**
* This is the ACM problem solving program for hihoCoder 1310.
*
* @version 2017-04-26
* @author Zhang Yufei.
*/
public class HihoCoder1310 {
/**
* Record the information of island.
*/
private static class Island implements
Comparable<Island> {
int area;
String shape;
@Override
public int compareTo(Island o) {
if (area < o.area) {
return -1;
} else if (area > o.area) {
return 1;
} else {
return shape.compareTo(o.shape);
}
}
}
/**
* Input data.
*/
private static int N, M;
/**
* The map of the islands.
*/
private static char[][] map;
/**
* Mark if the island has been visited.
*/
private static int[][] tags;
/**
* Record the range in x and y coordinates of a island.
*/
private static int maxX, minX, maxY, minY;
/**
* The area of a island;
*/
private static int area;
/**
* The main program.
*
* @param args
* The command line parameters list.
*/
public static void main(String[] args) {
// Input
Scanner scan = new Scanner(System.in);
N = scan.nextInt();
M = scan.nextInt();
map = new char[N][];
tags = new int[N][M];
for (int i = 0; i < N; i++) {
map[i] = scan.next().toCharArray();
for (int j = 0; j < M; j++) {
tags[i][j] = -1;
}
}
scan.close();
// DFS
List<Island> islands = new ArrayList<>();
int cnt = 0;
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
if (map[i][j] == '#' && tags[i][j] == -1) {
cnt++;
maxX = minX = maxY = minY = -1;
area = 0;
dfs(i, j, cnt);
Island island = new Island();
island.area = area;
island.shape = getShape(cnt);
islands.add(island);
}
}
}
// Compute.
Object[] islandsArray = islands.toArray();
Arrays.sort(islandsArray);
int areaCnt, shapeCnt;
areaCnt = shapeCnt = 1;
for (int i = 1; i < islandsArray.length; i++) {
Island cur = (Island) islandsArray[i];
Island pre = (Island) islandsArray[i - 1];
if (cur.area != pre.area) {
areaCnt++;
}
if (!cur.shape.equals(pre.shape)) {
shapeCnt++;
}
// System.out.println(cur.shape);
}
System.out.println(islandsArray.length + " "
+ areaCnt + " " + shapeCnt);
}
/**
* Using DFS to find island.
*
* @param x
* The x coordinate.
* @param y
* The y coordinate.
* @param tag
* The tag for this island.
*/
private static void dfs(int x, int y, int tag) {
tags[x][y] = tag;
area++;
if (maxX == -1 || maxX < x) {
maxX = x;
}
if (minX == -1 || minX > x) {
minX = x;
}
if (maxY == -1 || maxY < y) {
maxY = y;
}
if (minY == -1 || minY > y) {
minY = y;
}
if (x - 1 >= 0 && map[x - 1][y] == '#'
&& tags[x - 1][y] == -1) {
dfs(x - 1, y, tag);
}
if (x + 1 < N && map[x + 1][y] == '#'
&& tags[x + 1][y] == -1) {
dfs(x + 1, y, tag);
}
if (y - 1 >= 0 && map[x][y - 1] == '#'
&& tags[x][y - 1] == -1) {
dfs(x, y - 1, tag);
}
if (y + 1 < M && map[x][y + 1] == '#'
&& tags[x][y + 1] == -1) {
dfs(x, y + 1, tag);
}
}
private static String getShape(int tag) {
StringBuilder builder = new StringBuilder();
builder.append(maxX - minX + 1);
builder.append(",");
builder.append(maxY - minY + 1);
builder.append(":");
for (int i = minX; i <= maxX; i++) {
for (int j = minY; j <= maxY; j++) {
if (tags[i][j] == tag) {
builder.append('#');
} else {
builder.append('.');
}
}
}
return builder.toString();
}
}