본문 바로가기

자바 자료구조 알고리즘/DFS & BFS

코딩 테스트 Java BFS 활용 문제 풀기

개요 목적

Java BFS 기초 이해와 문제 풀이 해당 글에서는 재귀함수와 BFS기초를 알아보았다.

이번 시간에는 BFS 활용 문제를 풀면서 BFS 문제 풀이 실력을 늘려보자.

동전 교환

3

1 2 5

15

풀이

최소 개수를 구하는 문제이기 때문에, BFS를 사용하는 것이 유리하다.

DFS의 경우, 1,2,5로 시작할 때, 1+1+1+1+1 1에서 1을 더하는 모든 경우의 수를 구한 후에, 값이 나오지 않으면, 2로 넘어가고 5로 넘어간다.

반면에, BFS는 L=1인경우 동전을 하나 사용했을 경우 합을 구한 후에 답이 없다면, L=2 동전 두개 사용한 경우 합을 구하는 방식으로 메소드가 진행된다. 그래서 동전을 3개 사용했을 때, 5+5+5를 구하는 경우의 수를 빠르게 찾을 수 있다.

import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;

public class 동전교환 {
    static int n, m;
    static int[] arr;

    public static int BFS() {
        Queue<Integer> queue = new LinkedList();
        for (int i : arr) {
            queue.add(i);
        }
        int L = 1;
        //L=1부터 시작 동전 1개만 쓸경우 {1,2,5}
        while (!queue.isEmpty()) {
            int len = queue.size();
            //L=1일 때는 3개만 뽑아서 해야한다.
            //L=2인 경우는, 9개
            for (int i = 0; i < len; i++) {
                Integer cv = queue.poll();
                for (int n : arr) {
                    int nv = cv + n;
                    if (nv == m) {
                        return L + 1;
                    }
                    queue.add(nv);
                }
            }
            L++;
        }
        return 0;
    }

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        n = sc.nextInt();
        arr = new int[n];
        for (int i = 0; i < arr.length; i++) {
            arr[i] = sc.nextInt();
        }
        m = sc.nextInt();
        int answer = BFS();
        System.out.println(answer);
    }
}

미로의 최단거리 통로

0 0 0 0 0 0 0 0

1 1 1 1 1 0 0 0

0 1 0 0 0 1 1 0

1 0 1 1 1 1 0 1

0 0 0 1 0 0 0 1

0 0 1 0 1 0 0 0 0

풀이

import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;

public class 미로의최단거리 {

    static int[][] board, dis;
    static int[] dx={-1, 0, 1, 0};
    static int[] dy={0, 1, 0, -1};

    static class Point{
        public int x, y;
        public Point(int x, int y) {
            this.x = x;
            this.y = y;
        }
    }
    public static void BFS(int x, int y) {
        Queue<Point> Q=new LinkedList<>();
        Q.offer(new Point(x, y));
        board[x][y]=1;
        while (!Q.isEmpty()) {
            Point tmp = Q.poll();
            for (int i = 0; i < 4; i++) {
                int nx=tmp.x+dx[i];
                int ny=tmp.y+dy[i];
                //다음 갈곳이 1보다 크고 7보다 작으며, 지나가지 않은 곳일 때
                if(nx>=1 && nx<=7 && ny>=1 && ny<=7 && board[nx][ny]==0){
                    board[nx][ny]=1; //아에 보드에 이미 간곳이라고 표시해도 괜찮다. 최소의 값을 구하는 것이기 때문에
                    Q.offer(new Point(nx, ny));
                    //기존 값에 +1해서 값을 저장한다.
                    dis[nx][ny]=dis[tmp.x][tmp.y]+1;
                }
            }
        }
    }
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        board=new int[8][8];
        dis=new int[8][8];
        for(int i=1; i<=7; i++){
            for(int j=1; j<=7; j++){
                board[i][j]=sc.nextInt();
            }
        }
        BFS(1, 1);
        if(dis[7][7]==0) System.out.println(-1);
        else System.out.println(dis[7][7]);
    }
}

처음 que에 (0,0)이 있을 때는, (1,0) 하고 (0,1) dis 에 0+1한값을 추가하고, que에(1,0)과 (0,1)을 추가한다.

que에 (1,0)(1,0)이 있을 때는, (2,0)과 (0,2) dis에 1+1한 값을 추가하고, que(2,0)과 (0,2)를 추가해서 BFS 계속 진행한다. 이런 방법의 반복으로 (7,7) dis 값을 채운다. que가 empty될 때까지.

토마토

6 4

0 0 -1 0 0 0

0 0 1 0 -1 0

0 0 -1 0 0 0

0 0 0 0 -1 1

풀이

먼저 Q값에 board토마토 상자에 익어 있는 토마토 위치를 넣는다.

이 토마토 위치들을 시작으로 사방으로 다른 토마토를 익히면서, 익혀진 토마토들은 다시 다른 토마토를 익히기 위해 Q에 위치 정보를 넣는다.

Q가 완전히 비어지게 되면, 토마토들의 사방 익힘이 끝난 것을 알 수 있다.

Q가 끝나도 익지 않은 토마토가 있다면 그것은 영원히 익지 않은 토마토인 것이다.

import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;

public class 토마토 {
    static int[] dx={-1, 0, 1, 0};
    static int[] dy={0, 1, 0, -1};
    static int m, n;
    static int[][] board, dis;
    static Queue<Point> Q = new LinkedList<>();

    static class Point {
        public int x, y;
        Point(int x, int y){
            this.x=x;
            this.y=y;
        }
    }

    public static void BFS() {
        //Q가 다 빌 때가지 실행하면, Q가 끝나고도 board 토마토 상자 안에 0이 존재하면 영원히 익지 않는 경우다
        while (!Q.isEmpty()) {
            Point tmp = Q.poll();
            for (int i = 0; i < 4; i++) {
                int nx = tmp.x+dx[i];
                int ny = tmp.y + dy[i];
                if (nx >= 0 && nx < n && ny >= 0 && ny < m && board[nx][ny] == 0) {
                    board[nx][ny] = 1;
                    dis[nx][ny] = dis[tmp.x][tmp.y] + 1;
                    //다음 사방향 토마토를 익히게 할 익은 토마토 위치를 Q에 넣는다. 
                    Q.offer(new Point(nx, ny));
                }
            }
        }
    }

    public static void main(String[] args) {
        Scanner kb = new Scanner(System.in);
        m=kb.nextInt(); //열
        n=kb.nextInt(); //행
        board=new int[n][m];
        dis=new int[n][m];
        for(int i=0; i<n; i++){
            for(int j=0; j<m; j++){
                board[i][j]=kb.nextInt();
                //토마토 상자 안을 채울 때, 먼저 익어 있는 토마토 위치를 Q에 넣는다.
                //여기서 부터 시작해서, 사방향 익히게할 시작 점이 되고, 익힌 토마토들은 또 Q목록에 넣는다.
                if(board[i][j]==1) Q.offer(new Point(i, j));
            }
        }

        boolean flag=true;
        int answer=Integer.MIN_VALUE;
        for(int i=0; i<n; i++){
            for(int j=0; j<m; j++){
                if(board[i][j]==0) flag=false;
            }
        }
        if(flag){
            for(int i=0; i<n; i++){
                for(int j=0; j<m; j++){
                    answer=Math.max(answer, dis[i][j]);
                }
            }
            System.out.println(answer);
        }
        else System.out.println(-1);
    }
}

섬 나라 아일랜드

7

1 1 0 0 0 1 0

0 1 1 0 1 1 0

0 1 0 0 0 0 0

0 0 0 1 0 1 1

1 1 0 1 1 0 0

1 0 0 0 1 0 0

1 0 1 0 1 0 0

풀이

import java.util.*;
class Point{
	int x, y;
	Point(int x, int y){
		this.x=x;
		this.y=y;
	}
}
class Main {
	static int answer=0, n;
	static int[] dx={-1, -1, 0, 1, 1, 1, 0, -1};
	static int[] dy={0, 1, 1, 1, 0, -1, -1, -1};
	Queue<Point> queue = new LinkedList<>();
	public void BFS(int x, int y, int[][] board){
		queue.add(new Point(x, y));
		while(!queue.isEmpty()){
			Point pos = queue.poll();
			for(int i=0; i<8; i++){
				int nx=pos.x+dx[i];
				int ny=pos.y+dy[i];
				if(nx>=0 && nx<n && ny>=0 && ny<n && board[nx][ny]==1){
					board[nx][ny]=0;
					queue.add(new Point(nx, ny));
				}
			}		
		}
	}

	public void solution(int[][] board){	
		for(int i=0; i<n; i++){
			for(int j=0; j<n; j++){
				if(board[i][j]==1){
					answer++;
					board[i][j]=0;
					BFS(i, j, board);
				}
			}
		}
	}

	public static void main(String[] args){
		Main T = new Main();
		Scanner kb = new Scanner(System.in);
		n=kb.nextInt();
		int[][] arr=new int[n][n];
		for(int i=0; i<n; i++){
			for(int j=0; j<n; j++){
				arr[i][j]=kb.nextInt();
			}
		}
		T.solution(arr);
		System.out.println(answer);
	}
}