package org.example.섬의개수;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.text.MessageFormat;
import java.util.LinkedList;
import java.util.Objects;
import java.util.Queue;
import java.util.StringTokenizer;
/* *
*
*
*
*
* */
public class Main {
public static void main(String[] args) {
FastReader fr = new FastReader();
while (true) {
int w = fr.nextInt();
int h = fr.nextInt();
if (w == 0 && h == 0) {
break;
}
Area[][] areas = new Area[h][w];
for (int x = 0; x < h; x++) {
for (int y = 0; y < w; y++) {
int type = fr.nextInt();
areas[x][y] = new Area(w, h, x, y, type);
}
}
// bfs 탐색하면서 같은 type 의 area 를 찾는다.
// 찾은 area 는 visited 로 변경한다.
// bfs 탐색이 끝나면 섬의 개수를 증가시킨다.
// 모든 area 를 탐색할 때까지 반복한다.
int count = 0;
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
Area start = areas[i][j];
if (start.isNotVisited() && start.isLand()) {
start.bfs(areas);
count++;
}
}
}
System.out.println(count);
}
}
public static class Area extends Square {
private static final int[] dx = {0, 0, 1, -1, 1, 1, -1, -1};
private static final int[] dy = {1, -1, 0, 0, -1, 1, 1, -1};
private static final int WAY_LENGTH = dx.length;
private final int x;
private final int y;
private final int type;
private boolean visited;
public Area(int w, int h, int x, int y, int type) {
super(w, h);
if (dx.length != dy.length) {
String errorMessage = MessageFormat.format("dx, dy 의 길이는 같아야 합니다. dx: {0}, dy: {1}", dx.length, dy.length);
throw new IllegalArgumentException(errorMessage);
}
if (!(0 <= x && x < h && 0 <= y && y < w)) {
String errorMessage = MessageFormat.format("x는 0 이상 {0} 미만의 양의 정수 y는 0이상 {1} 미만의 양의 정수여야합니다. . x: {2}, y: {3}", h, w, x, y);
throw new IllegalArgumentException(errorMessage);
}
if (!(0 <= type && type <= 1)) {
String errorMessage = MessageFormat.format("type은 0 또는 1이어야 합니다. type: {0}", type);
throw new IllegalArgumentException(errorMessage);
}
this.x = x;
this.y = y;
this.type = type;
}
public boolean bfs(Area[][] areas) {
Objects.requireNonNull(areas, "areas 는 null 일 수 없습니다.");
Queue<Area> queue = new LinkedList<>();
queue.add(this);
this.visited = true;
while (!queue.isEmpty()) {
Area current = queue.poll();
for (int i = 0; i < WAY_LENGTH; i++) {
int nx = current.x + dx[i];
int ny = current.y + dy[i];
if (!(0 <= nx && nx < h && 0 <= ny && ny < w)) {
continue;
}
Area next = areas[nx][ny];
if (next.isLand() && next.isNotVisited()) {
next.visited = true;
queue.add(areas[nx][ny]);
}
}
}
return true;
}
private boolean isNotVisited() {
return !this.visited;
}
private boolean isLand() {
return this.type == 1;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Area)) return false;
Area area = (Area) o;
if (x != area.x) return false;
if (y != area.y) return false;
if (type != area.type) return false;
return visited == area.visited;
}
@Override
public int hashCode() {
int result = x;
result = 31 * result + y;
result = 31 * result + type;
result = 31 * result + (visited ? 1 : 0);
return result;
}
}
public static class Square {
protected final int w;
protected final int h;
public Square(int w, int h) {
if (!(1 <= w && w <= 50 && 1 <= h && h <= 50)) {
String errorMessage = MessageFormat.format("w, h 는 1 이상 50 이하의 정수여야 합니다. w: {0}, h: {1}", w, h);
throw new IllegalArgumentException(errorMessage);
}
this.w = w;
this.h = h;
}
}
public static class FastReader {
BufferedReader br;
StringTokenizer st;
public FastReader() {
br = new BufferedReader(new InputStreamReader(System.in));
}
public String next() {
while (Objects.isNull(st) || !st.hasMoreElements()) {
try {
st = new StringTokenizer(br.readLine());
} catch (IOException e) {
throw new RuntimeException(e);
}
}
return st.nextToken();
}
public int nextInt() {
return Integer.parseInt(next());
}
}
}
Uploaded by N2T
'자바 > 알고리즘' 카테고리의 다른 글
[알고리즘]스택 수열 (0) | 2023.08.23 |
---|---|
[알고리즘]소수 구하기 (0) | 2023.08.19 |
[알고리즘]15651. N 과 M ( 3 ) (0) | 2023.08.17 |
[Java] 한수 (0) | 2023.08.15 |
프로그래머스 - 크레인 인형뽑기 게임 (0) | 2022.01.01 |