새소식

JAVA (개념, 알고리즘)

DFS, BFS 활용 (2)

  • -

1. 미로탐색(DFS)

 

7*7 격자판 미로를 탈출하는 경로의 가지수를 출력하는 프로그램을 작성하세요.

출발점은 격자의 (1, 1) 좌표이고, 탈출 도착점은 (7, 7)좌표이다. 격자판의 1은 벽이고, 0은 통로이다.

격자판의 움직임은 상하좌우로만 움직인다. 미로가 다음과 같다면

위의 지도에서 출발점에서 도착점까지 갈 수 있는 방법의 수는 8가지이다.

 

입력

7*7 격자판의 정보가 주어집니다.

 

출력

첫 번째 줄에 경로의 가지수를 출력한다.

예시 입력 1 

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 0 0 0 1
1 1 0 1 1 0 0
1 0 0 0 0 0 0

예시 출력 1

8

<코드>

import java.util.*;
class Main {
    static int[] dx = {-1, 0, 1, 0};
    static int[] dy = {0, 1, 0, -1};
    static int[][] board;
    static int answer=0;
    public void DFS(int x, int y)
    {
        if(x==7 && y==7)
            answer++;
        else {
            for (int i=0; i<4; i++) {
                int nx = x + dx[i];
                int ny = y + dy[i];
                if(nx >=1 && nx <= 7 && ny >=1 && ny <=7 && board[nx][ny]==0)
                {
                    board[nx][ny]=1;
                    DFS(nx,ny);
                    board[nx][ny]=0;
                }
            }
        }
    }

    public static void main(String[] args) {
        Main T = new Main();
        Scanner sc = new Scanner(System.in);
        board = new int[8][8];
        for(int i=1; i<=7; i++) {
            for (int j=1; j<=7; j++)
                board[i][j] = sc.nextInt();
        }
        board[1][1] = 1;
        T.DFS(1,1);
        System.out.println(answer);
    }
}

 

2. 토마토 (BFS 활용)

현수의 토마토 농장에서는 토마토를 보관하는 큰 창고를 가지고 있다. 토마토는 아래의 그림과 같이 격자 모양 상자의 칸에 하나씩 넣어서 창고에 보관한다. 창고에 보관되는 토마토들 중에는 잘 익은 것도 있지만, 아직 익지 않은 토마토들도 있을 수 있다. 보관 후 하루가 지나면, 익은 토마토들의 인접한 곳에 있는 익지 않은 토마토들은 익은 토마토의 영향을 받아 익게 된다. 하나의 토마토의 인접한 곳은 왼쪽, 오른쪽, 앞, 뒤 네 방향에 있는 토마토를 의미한다. 대각선 방향에 있는 토마토들에게는 영향을 주지 못하며, 토마토가 혼자 저절로 익는 경우는 없다고 가정한다. 현수는 창고에 보관된 토마토들이 며칠이 지나면 다 익게 되는지, 그 최소 일수를 알고 싶어 한다.
토마토를 창고에 보관하는 격자모양의 상자들의 크기와 익은 토마토들과 익지 않은 토마토들의 정보가 주어졌을 때, 며칠이 지나면 토마토들이 모두 익는지, 그 최소 일수를 구하는 프로그램을 작성하라. 

단, 상자의 일부 칸에는 토마토가 들어있지 않을 수도 있다.

 

▣ 입력설명
첫 줄에는 상자의 크기를 나타내는 두 정수 M, N이 주어진다. M은 상자의 가로 칸의 수, N은 상자의 세로 칸의 수를 나타낸다. 단, 2 ≤ M, N ≤ 1,000 이다. 
둘째 줄부터는 하나의 상자에 저장된 토마토들의 정보가 주어진다. 즉, 둘째 줄부터 N개의 줄에는 상자에 담긴 토마토의 정보가 주어진다. 하나의 줄에는 상자 가로줄에 들어있는 토마토의 상태가 M개의 정수로 주어진다. 정수 1은 익은 토마토, 정수 0은 익지 않은 토마토, 정수 -1은 토마토가 들어있지 않은 칸을 나타낸다. 

 

▣ 출력설명
여러분은 토마토가 모두 익을 때까지의 최소 날짜를 출력해야 한다. 만약, 저장될 때부터 모든 토마토가 익어있는 상태이면 0을 출력해야 하고, 토마토가 모두 익지는 못하는 상황이면 -1을 출력해야 한다.

 

▣ 입력예제 1 
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

 

▣ 출력예제 1
4

 

출처 : 한국정보올림피아드

 

<코드>

import java.util.*;

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

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

    public void BFS() {
        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;
                    Q.offer(new Point(nx, ny));
                    dis[nx][ny] = dis[tmp.x][tmp.y]+1;
                }
            }
        }
    }
    public static void main(String[] args) {
        Main T = new Main();
        Scanner sc = new Scanner(System.in);
        m = sc.nextInt();
        n = sc.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] = sc.nextInt();
                if(board[i][j] == 1)
                    Q.offer(new Point(i,j));
            }
        }
        T.BFS();
        boolean flag = true; // 전체가 익지 않은 상황을 보기 위한 flag 변수
        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);
    }
}

 

3. 섬나라 아일랜드(DFS, BFS 풀이 방법)

N*N의 섬나라 아일랜드의 지도가 격자판의 정보로 주어집니다. 각 섬은 1로 표시되어 상하좌우와 대각선으로 연결되어 있으며, 0은 바다입니다. 섬나라 아일랜드에 몇 개의 섬이 있는지 구하는 프로그램을 작성하세요.


만약 위와 같다면 섬의 개수는 5개입니다. 

 

▣ 입력설명
첫 번째 줄에 자연수 N(3<=N<=20)이 주어집니다.
두 번째 줄부터 격자판 정보가 주어진다.

 

▣ 출력설명
첫 번째 줄에 섬의 개수를 출력한다.

 

▣ 입력예제 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

 

▣ 출력예제 1
5

 

<1. DFS 풀이방법(코드)>

import java.util.*;

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

class Main {
    static int[] dx = {-1, 0, 1, 0, -1, -1, 1, 1};
    static int[] dy = {0, -1, 0, 1, -1, 1, -1, 1};
    static int n, answer=0;
    static Queue<Point> Q = new LinkedList<>();

    public void DFS(int x, int y, int[][] board) {
        //만나는 섬들을 모두 0으로 바꿔준다.
        for(int i=0; i<8; i++) {
            int nx = x + dx[i];
            int ny = y + dy[i];
            if (nx >= 0 && nx<n && ny>=0 && ny < n && board[nx][ny]==1)
            {
                board[nx][ny]=0;
                DFS(nx,ny, board);
            }
        }
    }

    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; // 출발점을 0으로 바꾼 후 넘긴다.
                    DFS(i, j, board);
                }
            }
        }
    }

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

<2. BFS 풀이방법(코드)>

import java.util.*;

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

class Main {
    static int[] dx = {-1, 0, 1, 0, -1, -1, 1, 1};
    static int[] dy = {0, -1, 0, 1, -1, 1, -1, 1};
    static int n, answer=0;
    static Queue<Point> Q = new LinkedList<>();

    public void BFS(int x, int y, int[][] board) {
        Q.add(new Point(x,y)); // 출발점을 큐에 추가한다.

        while(!Q.isEmpty())
        {
            Point pos = Q.poll();
            //만나는 섬들을 모두 0으로 바꿔준다.
            for(int i=0; i<8; i++) {
                int nx = x + dx[i];
                int ny = y + dy[i];
                if (nx >= 0 && nx<n && ny>=0 && ny < n && board[nx][ny]==1)
                {
                    board[nx][ny]=0;
                    Q.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; // 출발점을 0으로 바꾼 후 넘긴다.
                    BFS(i, j, board);
                }
            }
        }
    }

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

 

4. 피자 배달 거리 (삼성 SW 역량 평가 기출문제 : DFS 활용)

N×N 크기의 도시지도가 있습니다. 도시지도는 1×1크기의 격자칸으로 이루어져 있습니다. 각 격자칸에는 0은 빈칸, 1은 집, 2는 피자집으로 표현됩니다. 각 격자칸은 좌표(행번호, 열 번호)로 표현됩니다. 행번호는 1번부터 N번까지이고, 열 번호도 1부터 N까지입니다. 도시에는 각 집마다 “피자배달거리”가 았는데 각 집의 피자배달거리는 해당 집과 도시의 존재
하는 피자집들과의 거리 중 최소값을 해당 집의 “피자배달거리”라고 한다.

집과 피자집의 피자배달거리는 |x1-x2|+|y1-y2| 이다. 예를 들어, 도시의 지도가 아래와 같다면


(1, 2)에 있는 집과 (2, 3)에 있는 피자집과의 피자 배달 거리는 |1-2| + |2-3| = 2가 된다.
최근 도시가 불경기에 접어들어 우후죽순 생겼던 피자집들이 파산하고 있습니다. 도시 시장은 도시에 있는 피자집 중 M개만 살리고 나머지는 보조금을 주고 폐업시키려고 합니다. 시장은 살리고자 하는 피자집 M개를 선택하는 기준으로 도시의 피자배달거리가 최소가 되는 M개의 피자집을 선택하려고 합니다.

도시의 피자 배달 거리는 각 집들의 피자 배달 거리를 합한 것을 말합니다.


▣ 입력설명
첫째 줄에 N(2 ≤ N ≤ 50)과 M(1 ≤ M ≤ 12)이 주어진다.
둘째 줄부터 도시 정보가 입력된다.

 

▣ 출력설명
첫째 줄에 M개의 피자집이 선택되었을 때 도시의 최소 피자배달거리를 출력한다.

 

▣ 입력예제 1 
4 4
0 1 2 0
1 0 2 1
0 2 1 2
2 0 1 2

 

▣ 출력예제 1
6

 

<코드>

import java.util.*;
class Point {
    int x,y;
    public Point (int x, int y) {
        this.x=x;
        this.y=y;
    }
}

class Main {
    static int n,m,len;
    static int[] combi;
    static int answer = Integer.MAX_VALUE; // 최소 피자배달거리 저장.
    static ArrayList<Point> pz, hs; // 피자, 집 좌표
    public void DFS(int L, int s)
    {
        if(L==m)
        {
            int sum=0;
            for(Point h : hs) {
                //모든 집의 좌표가 Point 객체로 돈다.
                //h의 x, y 좌표는 h.x, h.y 로 결정된다.
                int dis = Integer.MAX_VALUE;
                for(int i : combi) {
                    // for문을 돌면서 combi 안에 최소값을 구한다.
                    dis = Math.min(dis, Math.abs(h.x-pz.get(i).x) + Math.abs(h.y-pz.get(i).y));
                }
                //dis는 이 집의 최소배달거리가 된다.
                sum += dis; // 도시의 피자배달거리
            }
            answer = Math.min(answer, sum);
        }

        else {
            for(int i=s; i<len; i++) {
                combi[L]=i;
                DFS(L+1, i+1); // 조합 경우의 수가 구해진다.
            }
        }
    }

    public static void main(String[] args) {
        Main T = new Main();
        Scanner sc = new Scanner(System.in);

        n = sc.nextInt();
        m = sc.nextInt();
        pz = new ArrayList<>();
        hs = new ArrayList<>();

        for(int i=0; i<n; i++) {
            for (int j=0; j<m; j++) {
                int tmp = sc.nextInt();
                if (tmp==1) hs.add(new Point(i, j));
                else if (tmp==2) pz.add(new Point(i, j));
            }
        }
        
        len = pz.size();
        combi = new int[m];
        // 궁극적으로 하고자하는 것은 lenCm 의 조합 개수를 구하는 것임. 
        // 윗줄 주석에서 (C는 수학 조합 기호)를 의미한다.
        T.DFS(0,0);
        System.out.println(answer);
    }
}

 

Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.