Silver
문제
<그림 1>과 같이 정사각형 모양의 지도가 있다.
1은 집이 있는 곳을, 0은 집이 없는 곳을 나타낸다.
철수는 이 지도를 가지고 연결된 집의 모임인 단지를 정의하고, 단지에 번호를 붙이려 한다.
여기서 연결되었다는 것은 어떤 집이 좌우, 혹은 아래위로 다른 집이 있는 경우를 말한다.
대각선상에 집이 있는 경우는 연결된 것이 아니다.
<그림 2>는 <그림 1>을 단지별로 번호를 붙인 것이다.
지도를 입력하여 단지수를 출력하고, 각 단지에 속하는 집의 수를 오름차순으로 정렬하여 출력하는 프로그램을 작성하시오.
입력
첫 번째 줄에는 지도의 크기 N(정사각형이므로 가로와 세로의 크기는 같으며 5≤N≤25)이 입력되고,
그 다음 N줄에는 각각 N개의 자료(0혹은 1)가 입력된다.
출력
첫 번째 줄에는 총 단지수를 출력하시오. 그리고 각 단지내 집의 수를 오름차순으로 정렬하여 한 줄에 하나씩 출력하시오.
풀이1 DFS
import java.util.*;
import java.io.*;
class Main {
static boolean[][] visited;
static char[][] map;
static int N;
static int count;
static int[] dx = {1, 0, -1, 0};
static int[] dy = {0, 1, 0, -1};
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
N = Integer.parseInt(br.readLine());
visited=new boolean[N][N];
map=new char[N][N];
for(int i=0; i<N; i++){
map[i] = br.readLine().toCharArray();
}
ArrayList<Integer> list = new ArrayList<>();
for(int i=0; i<N; i++){
for(int j=0; j<N; j++){
if(map[i][j]=='1'&&!visited[i][j]){
count = 0;
dfs(i, j);
list.add(count);
}
}
}
StringBuilder sb = new StringBuilder();
Collections.sort(list);
sb.append(list.size()).append("\n");
for(int i=0; i<list.size(); i++){
sb.append(list.get(i)).append("\n");
}
System.out.println(sb);
br.close();
}
public static void dfs(int x, int y){
count += 1;
visited[x][y] = true;
for(int i=0; i<4; i++){
int xx = x + dx[i];
int yy = y+dy[i];
if(xx<0 || xx >= N || yy<0 || yy >= N)
continue;
if(map[xx][yy]=='1'&&!visited[xx][yy]){
dfs(xx, yy);
}
}
}
}
해결방법
- 입력받은 값을 저장하기 위한 배열 map과 방문 여부를 기록하는 배열 visited를 생성한다.
- 맵을 탐색 하면서, 해당 좌표가 아직 방문되지 않았고 집이 있는 좌표(1)이면 깊이우선탐색을 하여 단지에 속한 집을 탐색하고, 집의 수를 count에 기록한다.
- 각 단지의 집의 수를 list에 기록하고, 오름차순 정렬한 후 출력한다.
풀이2 BFS ( 더 호율적! )
import java.util.*;
import java.io.*;
class Main {
static int[][] map;
static boolean[][] visited;
static int[] dx = {1, 0, -1, 0};
static int[] dy = {0, 1, 0, -1};
static int N;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
N = Integer.parseInt(br.readLine());
map = new int[N][N];
visited = new boolean[N][N];
for(int i=0; i<N; i++){
String str = br.readLine();
for(int j=0; j<N; j++){
if(str.charAt(j) == '1') map[i][j] = 1;
}
}
List<Integer> list = new ArrayList<>();
for(int i=0; i<N; i++){
for(int j=0; j<N; j++){
if(map[i][j] == 1 && !visited[i][j]){
list.add(bfs(i, j));
}
}
}
StringBuilder sb = new StringBuilder();
Collections.sort(list);
sb.append(list.size()).append("\n");
for(int i=0; i<list.size(); i++){
sb.append(list.get(i)).append("\n");
}
System.out.println(sb);
br.close();
}
public static int bfs(int x, int y){
Queue<int[]> q = new LinkedList<>();
visited[x][y] = true;
int count = 1;
q.offer(new int[] {x, y});
while(!q.isEmpty()){
int[] node = q.poll();
int qx = node[0];
int qy = node[1];
for(int i=0; i<4; i++){
int xx = dx[i] + qx;
int yy = dy[i] + qy;
if(xx>=0 && xx<N && yy>=0 && yy<N && !visited[xx][yy] && map[xx][yy]==1){
visited[xx][yy] = true;
count += 1;
q.offer(new int[] {xx, yy});
}
}
}
return count;
}
}
DFS는 재귀 호출을 사용하여 구현되는데, 이때 재귀호출이 깊어지면 함수 호출 스택이 커지면서 스택 오버플로우가 발생할 수 있다.
반면 BFS는 큐를 사용하여 탐색을 진행하기 때문에, 오버플로우 위험이 없다.
- DFS는 재귀 호출의 깊이가 커지는 문제에서 스택 오버플로우 위험이 있으며, 최단 경로 탐색이 목적일 때는 적합하지 않다.
- BFS는 메모리 안정성 면에서 더 나으며, 최단 경로 문제나 넓은 영역을 탐색하는 문제에서 더 효율적이다.
https://www.acmicpc.net/problem/2667
'Algorithm > Baekjoon Oline Judge - Java' 카테고리의 다른 글
[백준] 1697_ 숨바꼭질 / 그래프, 최단경로, BFS (1) | 2024.10.19 |
---|---|
[백준] 1260_DFS와 BFS / DFS, BFS (0) | 2024.10.19 |
[백준] 2178_미로탐색 / BFS, 최단경로보장 (1) | 2024.09.18 |
[백준] 1012_유기농배추 / DFS, BFS, 상하좌우탐색 (0) | 2024.09.18 |
[백준] 2606_바이러스 / DFS 그래프 (1) | 2024.09.17 |