BOJ 2667) 단지번호붙이기
- [ 기타 ]/백준, 프로그래머스
- 2022. 2. 22.
문제를 보고 상하좌우 4방향을 검사하여 방문한 적이 없는 집이 하나도 없으면 새로 방문하는 단지로 풀면 되겠다 생각헸는데, 탐색 순서를 보면 문제 예제의 2번같은 경우 다른 쪽 끝을 먼저 탐색할 경우 단지의 개수를 증가시키는 연산을 하게되어 단지수를 정확하게 계산할 수 없게 되어 문제가 생긴다. 당연하게도 단지 내 집의 개수도 계산할 수 없다.
무엇보다도 이런 좌표탐색 문제의 경우 한 부분을 완료하고 다음 부분으로 넘어가야지 위와 같은 문제가 발생하지 않는다.
dfs가 떠오르지 않은 것은 아니지만 dfs는 사용하기 망설여지는게 input이 과하게 클경우 시간초과가 너무 많이나서 꺼려지게됨.
> DFS의 시간복잡도는 리스트의경우 O(|V|+|E|), 인접행렬의 경우 O(V^2)이므로
행렬의 최대크기가 25*25=625인 이문제의 경우 V^2의 시간복잡도를 가져도 괜찮다.
//접근을 잘못한 코드
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Scanner;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int N = Integer.parseInt(br.readLine());
//0: 집없음 1:방문X집
int[][] arr = new int[N][N];
boolean[][] visited = new boolean[N][N];
//주변 4개의 집이 모두 방문한적 없을경우 단지수++
boolean flag;
boolean edited = true;
int rst = 0;
for(int i=0; i<N; i++) {
String str = br.readLine();
for(int j=0; j<N; j++) {
arr[i][j] = str.charAt(j)-'0';
}
}
while(edited) {
edited=false;
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
if (arr[i][j] == 1 && !visited[i][j]) {
visited[i][j] = true;
flag = true;
//4방향중에 한곳이라도 방문한적 있을경우 flag=false;
if (i > 0 && visited[i-1][j]) {
flag = false;
}
if (j > 0 && visited[i][j-1]) {
flag = false;
}
if (i < N-1 && visited[i+1][j]) {
flag = false;
}
if (j < N-1 && visited[i][j+1]) {
flag = false;
}
//4방향에 방문하지 않은 집이 존재할 경우
if (i > 0 && arr[i-1][j] == 1) {
edited = true;
}
if (j > 0 && arr[i][j-1] == 1) {
edited = true;
}
if (i < N-1 && arr[i+1][j] == 1) {
edited = true;
}
if (j < N-1 && arr[i][j+1] == 1) {
edited = true;
}
if (flag) rst++;
}
}
}
}
System.out.println(rst);
}
}
//최종 코드
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Stack;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int N = Integer.parseInt(br.readLine());
//0: 집없음 1: 방문X집
int[][] arr = new int[N][N];
boolean[][] visited = new boolean[N][N];
Stack<Location> stack = new Stack();
List<Integer> list = new ArrayList<>();
int rst = 0;
//input 받기
for(int i=0; i<N; i++) {
String str = br.readLine();
for(int j=0; j<N; j++) {
arr[i][j] = str.charAt(j)-'0';
}
}
for(int i=0; i<N; i++) {
for(int j=0; j<N; j++) {
if(arr[i][j]==1 && !visited[i][j]) {
Location loc = new Location(i,j);
stack.push(loc);
int houseNum = 0;
visited[i][j] = true;
houseNum++;
while(!stack.isEmpty()) {
Location peekLoc = stack.peek();
int x = peekLoc.x;
int y = peekLoc.y;
boolean flag = true;
if(x>0 && arr[x-1][y]==1 && !visited[x-1][y]) {
visited[x-1][y] = true;
houseNum++;
Location l = new Location(x-1, y);
stack.push(l);
flag = false;
}
if(y>0 && arr[x][y-1]==1 && !visited[x][y-1]) {
visited[x][y-1] = true;
houseNum++;
Location l = new Location(x, y-1);
stack.push(l);
flag = false;
}
if(x<N-1 && arr[x+1][y]==1 && !visited[x+1][y]) {
visited[x+1][y] = true;
houseNum++;
Location l = new Location(x+1, y);
stack.push(l);
flag = false;
}
if(y<N-1 && arr[x][y+1]==1 && !visited[x][y+1]) {
visited[x][y+1] = true;
houseNum++;
Location l = new Location(x, y+1);
stack.push(l);
flag = false;
}
if(flag) stack.pop();
}
rst++;
list.add(houseNum);
}
}
}
System.out.println(rst);
Collections.sort(list);
for (Integer integer : list) {
System.out.println(integer);
}
}
static class Location {
int x;
int y;
public Location(int x, int y) {
this.x = x;
this.y = y;
}
}
}
스택을 이용한 dfs로 구현하였다. 집들을 탐색하다가 1이 보이면 그 집에서 연결되는 모든 노드들을 묶어서 한개의 단지를 만드는 방식으로 구현함.
조심할 점은 스택으로 dfs를 구현할때 초기값 설정은 반드시 while문 전에 시행되어야 함. while문내에서 초기화를 할경우 그부분이 반복되면서 의도치 않게 동작할 수 있다.
또 dfs에서 확장이 이루어지는 노드인지, leaf인지 여부를 확인해야 할 경우 flag변수를 별도로 선언해서 확인했는데, 이거말고 다른 방법은 없을까
'[ 기타 ] > 백준, 프로그래머스' 카테고리의 다른 글
BOJ 10026) 적록색약 (0) | 2022.06.26 |
---|---|
BOJ 2981) 검문 (0) | 2022.06.24 |
BOJ 1005) ACM Craft (0) | 2022.02.05 |
BOJ 2580) 스도쿠 (0) | 2022.01.14 |
BOJ 2156) 포도주 시식 (0) | 2022.01.03 |