N x M 크기의 얼음 틀이 있다. 구멍이 뚫려 있는 부분은 0, 칸막이가 존재하는 부분은 1로 표시된다. 구멍이 뚫려 있는 부분끼리 상,하,좌,우로 붙어 있는 경우 서로 연결되어 있는 것으로 간주한다. 이때 얼음 틀의 모양이 주어졌을 때 생성되는 총 아이스크림의 개수를 구하는 프로그램을 작성하시오.
🎁입력예시
4 5
00110
00011
11111
00000
🎊출력예시
3
이 문제는 DFS 혹은 BFS로 해결 할 수 있다. (모든 정점을 방문하기만 하면 되므로 둘 다 사용 가능) 얼음을 얼릴 수 있는 공간이 상, 하, 좌, 우로 연결되어있다고 표현 할 수 있으므로 그래프 형태로 모델링 가능하다. 방문처리 영역만 카운트하면 된다.
ex.
001
010
101
DFS를 활용한 알고리즘
import java.util.*;
public class Main {
public static int n, m;
// n * m 최대크기로 배열 생성해둔다.
public static int[][] graph = new int[1000][1000];
// DFS로 특정 노드를 방문하고 연결된 모든 노드들도 방문
public static boolean dfs(int x, int y) {
// 주어진 범위를 벗어나는 경우에는 즉시 종료
if (x <= -1 || x >=n || y <= -1 || y >= m) {
return false;
}
// 현재 노드를 아직 방문하지 않았다면
if (graph[x][y] == 0) {
// 해당 노드 방문 처리
graph[x][y] = 1;
// 상, 하, 좌, 우의 위치들도 모두 재귀적으로 호출 -> 해당 연속 영역 내에서 연결된 지점들이 연속적으로 방문처리된다.
// 상, 하, 좌, 우 호출에 대해서는 리턴값을 사용하지 않으므로 단순히 영역 내 연결된 모든 노드들에 대해 방문처리만 수행
dfs(x - 1, y);
dfs(x, y - 1);
dfs(x + 1, y);
dfs(x, y + 1);
return true;
}
return false;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
// N, M을 공백을 기준으로 구분하여 입력 받기
n = sc.nextInt();
m = sc.nextInt();
sc.nextLine(); // 버퍼 지우기
// 2차원 리스트의 맵 정보 입력 받기
for (int i = 0; i < n; i++) {
String str = sc.nextLine();
for (int j = 0; j < m; j++) {
graph[i][j] = str.charAt(j) - '0';
}
}
// 모든 노드(위치)에 대하여 DFS호출하여 음료수 채우기
// -> 막힌 칸막이 때문에 모든 위치에 대하여 for문을 돌려야함
int result = 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
// 현재 위치에서 DFS 수행
// -> 각 연속 영역의 첫 시작 지점만 result에 카운트된다.
if (dfs(i, j)) {
result += 1;
}
}
}
System.out.println(result); // 정답 출력
}
}
동빈이는 N * M 크기의 직사각형 형태의 미로에 갇혔습니다. 미로에는 여러 마리의 괴물이 있어 이를 피해 탈출해야 합니다.
동빈이의 위치는 (1, 1) 이며 미로의 출구는 (N, M)의 위치에 존재하며 한 번에 한 칸씩 이동할 수 있습니다. 이때 괴물이 있는 부분은 0으로 괴물이 없는 부분은 1로 표시되어 있습니다. 미로는 반드시 탈출할 수 있는 형태로 제시됩니다.
이때 동빈이가 탈출하기 위해 움직여야 하는 최소 칸의 개수를 구하세요. 칸을 셀 때는 시작 칸과 마지막 칸을 모두 포함해서 계산합니다.
🎁입력조건
첫째 줄에 두 정수 N, M(4<=N, M<=200)이 주어집니다. 다음 N개의 줄에는 각각 M개의 정수(0 혹은 1)로 미로의 정보가 주어집니다. 각각의 수들은 공백 없이 붙여서 입력으로 제시됩니다. 또한 시작 칸과 마지막 칸은 항상 1입니다.
🎊출력조건
첫째 줄에 최소 이동 칸의 개수를 출력합니다.
🎁입력예시
5 6
101010
111111
000001
111111
111111
🎊출력예시
10
[참고]
- (1, 2)에서 상하좌우 확인 시, 왼쪽의 시작 노드인 (1,1) 또한 1이므로 조건에 걸려서 3으로 값이 변경되면서 방문처리 되지만, 마지막 (n, m)의 값만 확인하면 되기 때문에 다른 노드들은 값이 변경되어도 상관없음
- 만약 특정 노드 상하좌우에 1 값을 가진 두 노드가 존재한다고 해도 두 노드 모두 똑같은 값으로 변경 될 것이다. 하지만 마찬가지로 마지막 (n, m)의 값만 확인하면 되기 때문에 다른 노드들은 값이 변경되어도 상관없다.
import java.util.*;
class Node {
private int x;
private int y;
public Node(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() {
return this.x;
}
public int getY() {
return this.y;
}
}
public class Main {
public static int n, m;
// n * m 최대크기로 배열 생성 해 둔다.
// 문제에서는 (1, 1)부터로 제시되어있지만 실제로 (0, 0)부터 데이터를 넣어도 상관없으므로 201 * 201일 필요 없다.
public static int[][] graph = new int[200][200];
// 이동할 네 가지 방향 정의 (상, 하, 좌, 우)
public static int dx[] = {-1, 1, 0, 0};
public static int dy[] = {0, 0, -1, 1};
public static int bfs(int x, int y) {
// 큐(Queue) 구현을 위해 queue 라이브러리 사용
// Node클래스 대신 int[] 사용해도 될 듯
Queue<Node> q = new LinkedList<>();
q.offer(new Node(x, y));
// 큐가 빌 때까지 반복하기
while(!q.isEmpty()) {
Node node = q.poll();
x = node.getX();
y = node.getY();
// 현재 위치에서 4가지 방향으로의 위치 확인
for (int i = 0; i < 4; i++) {
int nx = x + dx[i];
int ny = y + dy[i];
// 미로 찾기 공간을 벗어난 경우 무시
if (nx < 0 || nx >= n || ny < 0 || ny >= m) continue;
// 벽인 경우 무시
if (graph[nx][ny] == 0) continue;
// 해당 노드를 처음 방문하는 경우에만(첫 시작지점은 예외) 최단 거리 기록
if (graph[nx][ny] == 1) {
graph[nx][ny] = graph[x][y] + 1;
q.offer(new Node(nx, ny));
}
}
}
// 가장 오른쪽 아래까지의 최단 거리 반환
return graph[n - 1][m - 1];
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
// N, M을 공백을 기준으로 구분하여 입력 받기
n = sc.nextInt();
m = sc.nextInt();
sc.nextLine(); // 버퍼 지우기
// 2차원 리스트의 맵 정보 입력 받기
for (int i = 0; i < n; i++) {
String str = sc.nextLine();
for (int j = 0; j < m; j++) {
graph[i][j] = str.charAt(j) - '0';
}
}
// BFS를 수행한 결과 출력
System.out.println(bfs(0, 0));
}
}