프로그래머스 알고리즘

문제 설명

ROR 게임은 두 팀으로 나누어서 진행하며, 상대 팀 진영을 먼저 파괴하면 이기는 게임입니다. 따라서, 각 팀은 상대 팀 진영에 최대한 빨리 도착하는 것이 유리합니다.

지금부터 당신은 한 팀의 팀원이 되어 게임을 진행하려고 합니다. 다음은 5 x 5 크기의 맵에, 당신의 캐릭터가 (행: 1, 열: 1) 위치에 있고, 상대 팀 진영은 (행: 5, 열: 5) 위치에 있는 경우의 예시입니다.

위 그림에서 검은색 부분은 벽으로 막혀있어 갈 수 없는 길이며, 흰색 부분은 갈 수 있는 길입니다. 캐릭터가 움직일 때는 동, 서, 남, 북 방향으로 한 칸씩 이동하며, 게임 맵을 벗어난 길은 갈 수 없습니다.
아래 예시는 캐릭터가 상대 팀 진영으로 가는 두 가지 방법을 나타내고 있습니다.

  • 첫 번째 방법은 11개의 칸을 지나서 상대 팀 진영에 도착했습니다.

  • 두 번째 방법은 15개의 칸을 지나서 상대팀 진영에 도착했습니다.

위 예시에서는 첫 번째 방법보다 더 빠르게 상대팀 진영에 도착하는 방법은 없으므로, 이 방법이 상대 팀 진영으로 가는 가장 빠른 방법입니다.

만약, 상대 팀이 자신의 팀 진영 주위에 벽을 세워두었다면 상대 팀 진영에 도착하지 못할 수도 있습니다. 예를 들어, 다음과 같은 경우에 당신의 캐릭터는 상대 팀 진영에 도착할 수 없습니다.

게임 맵의 상태 maps가 매개변수로 주어질 때, 캐릭터가 상대 팀 진영에 도착하기 위해서 지나가야 하는 칸의 개수의 최솟값을 return 하도록 solution 함수를 완성해주세요. 단, 상대 팀 진영에 도착할 수 없을 때는 -1을 return 해주세요.

 

제한 사항

  • maps는 n x m 크기의 게임 맵의 상태가 들어있는 2차원 배열로, n과 m은 각각 1 이상 100 이하의 자연수입니다.
    • n과 m은 서로 같을 수도, 다를 수도 있지만, n과 m이 모두 1인 경우는 입력으로 주어지지 않습니다.
  • maps는 0과 1로만 이루어져 있으며, 0은 벽이 있는 자리, 1은 벽이 없는 자리를 나타냅니다.
  • 처음에 캐릭터는 게임 맵의 좌측 상단인 (1, 1) 위치에 있으며, 상대방 진영은 게임 맵의 우측 하단인 (n, m) 위치에 있습니다.

 

입출력 예

 

Maps answer
[[1,0,1,1,1],[1,0,1,0,1],[1,0,1,1,1],[1,1,1,0,1],[0,0,0,0,1]] 11
[[1,0,1,1,1],[1,0,1,0,1],[1,0,1,1,1],[1,1,1,0,0],[0,0,0,0,1]] -1
입출력 예 설명

입출력 예 #1
주어진 데이터는 다음과 같습니다.

캐릭터가 적 팀의 진영까지 이동하는 가장 빠른 길은 다음 그림과 같습니다.

따라서 총 11칸을 캐릭터가 지나갔으므로 11을 return 하면 됩니다.

 

입출력 예 #2
문제의 예시와 같으며, 상대 팀 진영에 도달할 방법이 없습니다. 따라서 -1을 return 합니다.

 

문제 풀이

bfs 를 사용해서 풀어야 합니다. bfs에 대한 개념은 *여기*를 클릭해서 확인하시면 됩니다.

 

솔직히 못풀겠어서 다른 사람들꺼 참고해서 따라해봤습니다.

 

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

public class gamemapShortcut {

    //위치를 가지고 있을 객체
    class Node {
        private int row;
        private int col;

        //생성자
        private Node(int row, int col) {
            this.row = row;
            this.col = col;
        }

        //getter
        public int getRow() {
            return row;
        }

        public int getCol() {
            return col;
        }
    }

    public int solution(int[][] maps) {
        Queue<Node> q = new LinkedList<>();
        //row 계산을 위해 상우하좌 순서로 지정
        int[] drow = {0, 1, 0, -1};
        //col 계산을 위해 상우하좌 순서로 지정
        int[] dcol = {-1, 0, 1, 0};
        int row = 0;
        int col = 0;
        //초기값을 큐에 저장
        q.offer(new Node(row, col));
        //큐가 없어질때까지 반복
        while (!q.isEmpty()) {
            Node now = q.poll();
            row = now.getRow();
            col = now.getCol();
            //좌표를 계산
            for (int i = 0; i < 4; i++) {
                int nrow = row + drow[i];
                int ncol = col + dcol[i];
                //다음 좌표가 map 안에 포함되어있고, 다음 위치에 한번도 가지 않았을 경우
                if (
                        nrow >= 0 && nrow < maps[0].length && ncol >= 0 && ncol < maps.length && maps[ncol][nrow] == 1) {
                    //이전까지 온 값을 다음 갈 위치에 누적 합
                    maps[ncol][nrow] = maps[col][row] + 1;
                    //다음 좌표를 큐에 넣음
                    q.offer(new Node(nrow, ncol));
                }
            }
        }
        //maps의 마지막 위치 저장하기
        int answer = maps[maps.length - 1][maps[0].length - 1];
        return answer == 1 ? -1 : answer;
        //마지막 위치에 도착하면 answer 리턴 아니면 -1리턴
    }





    public static void main(String[] args) {
        gamemapShortcut method = new gamemapShortcut();
        int arr[][] = {{1,0,1,1,1},{1,0,1,0,1},{1,0,1,1,1},{1,1,1,0,1},{0,0,0,0,1}};
        System.out.println(method.solution(arr));
    }
}



 

다름 사람 풀이 예시

import java.util.LinkedList;
import java.util.Queue;
import java.awt.Point;
class Solution {
    public static int solution(int[][] maps) {
        int X = maps[0].length;
        int Y = maps.length;
        boolean[][] visited = new boolean[Y][X];
        Queue<Point> q = new LinkedList<Point>();
        int x = 0;
        int y = 0;
        int size = 0;
        int cnt = 0;
        Point p = new Point();
        q.add(new Point(Y-1,X-1));
        while(q.isEmpty()==false) {
            size = q.size();
            cnt++;
            for(int i=0;i<size;i++)
            {
                p = q.peek();
                x = p.y;
                y = p.x;
                q.remove();
                if(visited[y][x]==true)
                    continue;
                maps[y][x] = 0;
                visited[y][x] = true;
                if(x==0 && y==0) {
                    return cnt;
                }
                if(x-1>-1 && maps[y][x-1]==1) { //왼쪽 한칸
                    q.add(new Point(y,x-1));
                }
                if(x+1<X && maps[y][x+1]==1) { //오른쪽 한칸
                    q.add(new Point(y,x+1));
                }
                if(y-1>-1 && maps[y-1][x]==1) { //위쪽 한칸
                    q.add(new Point(y-1,x));
                }
                if(y+1<Y && maps[y+1][x]==1) { //아래쪽 한칸
                    q.add(new Point(y+1,x));
                }
            }
        }
        return -1;
    }

BFS 너비 우선 탐색 Breadth First Search

최단거리 구하는 문제를 풀 때 유용합니다.

 

  • BFS는 시작 지점에서 가까운 노드부터 차례대로 그래프의 모든 노드를 탐색
  • BFS는 같은 레벨에 있는 노드들을 먼저 탐색하고 그다음 레벨 노드를 탐색함
  • 특정 노드에서 다른 노드까지 최단값 또는 임의의 경로를 찾을 때 사용
  • 스택이 아닌 큐(Queeu) 구조를 활용
  • FIFO 원칙으로 탐색

BFS 수행 과정

  1. 현재 레벨에 있는 root Node를 Q.offer에 넣어서 Q.size, 큐의 길이 계산
  2. 큐에서 꺼낸 노드와 인접한 노드들을 모두 방문
  3. 인접한 노드가 없으면 큐의 앞에서 노드를 꺼냄 (dequeue)
  4. 큐에 방문된 노드를 삽입 한다
  5. 큐에 가 공백 상태가 될 때까지 계속 한다 Q.isEmpty() = true 일 때 종료

 

활용 예제

 

Q. 그림과 같은 그래프에 대하여 정점의 개수 N, 연결선의 개수 M이 주어지고 그래프에 대한 연결 정보가 주어질 때, 시작정점 1에서 BFS 방문경로를 출력하시오.

 

그래프 정보

문제 풀이

 

시작 정점 1 bfs() 함수 실행, Queue를 이용하여 

다음 정점과 연결되어 있고 (map[x][i] ==1),

아직 방문하지 않은 정점 (visited[i] == false)

큐에 해당 정점을 넣어주고, 더 이상 방문할 저점이 존재하지 않으면 종료한다.

 

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
import java.util.Queue;
import java.util.LinkedList;

public class bfsprac {
    static int[][] map;
    static boolean[] visited;
    static StringTokenizer st;
    static int N, M, start, end;

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        N = Integer.parseInt(br.readLine()); // 정점의 개수
        M = Integer.parseInt(br.readLine()); // 간선의 개수

        map = new int[N+1][N+1];
        visited = new boolean[N+1]; // 방문 여부를 검사할 배열

        for (int m =0; m < M; m++){//그래프 정보 입력받기
            st = new StringTokenizer(br.readLine(), " ");
            start = Integer.parseInt(st.nextToken());
            end = Integer.parseInt(st.nextToken());
            map[start][end] =1;
            map[end][start] =1;
        }
        System.out.print("그래프 BFS 방문 순서 :");
        bfs(1);
    }

    static void bfs(int point) {
        Queue<Integer> queue = new LinkedList<>();
        queue.offer(point);
        visited[point] =true;

        while (!queue.isEmpty()) {
            int x = queue.poll();
            System.out.print(x+" ");

            for (int i =1; i<=N; i++){
                if (map[x][i] ==1 && visited[i]==false){ //다음 정점과 연결되어 있고 아직 방문하지 않았다면
                    queue.offer(i);
                    visited[i]=true;
                }
            }
        }
    }

}

Console

7
8
1 2
1 3
2 4
2 5
3 7
4 6
5 6
6 7
그래프 BFS 방문 순서 :1 2 3 4 5 7 6 

 

자바로 입력된 배열의 최소값과 최대값 구하기에 대해 알아보겠습니다.

for문과 향상된 for문을 사용해서 최소값 최대값을 구합니다.

 

 

변수 선언

int[] arr = {12,14,16,18,23,5,68}; //배열 예시

int min = Integer.MAX_VALUE; //int 타입 범위에서 가장 큰 수
int max = 0; //둘 중에 더 큰 수를 저장할겁니다..

min 값을 설정할 때 int타입 범위에서 가장 큰 수로 저장하면 굳이 배열에 대한 범위를 신경쓰지 않아도 됩니다.

둘중에 작은 수를 저장하게 됩니다.

 

Integer.MAX_VALUE    // int 타입의 최대값
Integer.MIN_VALUE     // int 타입의 최소값

 

자바로 최대값 최소값 구하기 for문

배열값과 min, max 값을 비교해서 최소값, 최대값을 구합니다.

intellij에서 fori 단축키를 사용하면 for문이 자동으로 입력됩니다.

//for문 사용
for (int i = 0; i < arr.length ; i++) {

    if (arr[i]<min)
        min = arr[i];

    if (arr[i]>max)
        max = arr[i];
}
System.out.println("for문 사용>> max:"+max+" min:"+min);

 

자바로 최대값 최소값 구하기 향상된 for문

향상된 for문을 사용해서 최대값과 최소값을 구한다.

intellij에서 iter 단축키를 사용하면 향상된 for문이 자동으로 입력됩니다.

//향상된 for문 사용
for (int i : arr) {

    if(i<min)
        min = i;

    if(i>max)
        max = i;
}
System.out.println("향상된 for문 사용>> max:"+max+ " min:"+min);

 

 

자바 최대값 최소값 구하기 전체 코드

public class maxMin {
    public static void main(String[] args) {

        int[] arr = {12,14,16,18,23,5,68}; //배열 예시

        int min = Integer.MAX_VALUE; //int 타입 범위에서 가장 큰 수
        int max = 0; //둘 중에 더 큰 수를 저장할겁니다..


        //for문 사용
        for (int i = 0; i < arr.length ; i++) {

            if (arr[i]<min)
                min = arr[i];

            if (arr[i]>max)
                max = arr[i];
        }
        System.out.println("for문 사용>> max:"+max+" min:"+min);


        //향상된 for문 사용
        for (int i : arr) {

            if(i<min)
                min = i;

            if(i>max)
                max = i;
        }
        System.out.println("향상된 for문 사용>> max:"+max+ " min:"+min);
    }
}

 

+ Recent posts