[JAVA/프로그래머스] 깊이/너비 우선 탐색(DFS/BFS): 여행경로

👀 문제

https://programmers.co.kr/learn/courses/30/lessons/43164

👊 도전

1. 설계

  1. DFS를 이용하여 티켓 경로를 찾는다

2. 구현

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
import java.util.*;
/**
 *
 * @author HEESOO
 *
 */
class Solution {
    int n; // 티켓 수
    boolean[] visit;
    ArrayList<String> list; // 최종 경로 저장
    String[][] map; // 티켓 참조 변수
    
    public String[] solution(String[][] tickets) {
        String[] answer = {};
        
        n=tickets.length;
        visit=new boolean[n];
        list=new ArrayList<>();
        map=tickets;
        
        for(int i=0;i<n;i++){
            if(tickets[i][0].equals("ICN")){ // 시작
                visit[i]=true; // 티켓 사용
                dfs(tickets[i][1], 1, new StringBuilder("ICN "));
                visit[i]=false; // 사용 안 할 경우
            }
        }
        
        Collections.sort(list); // 알파벳기준 오름차순 정렬
        return list.get(0).split(" "); // 첫번째 값 리턴
    }
    
    public void dfs(String dept, int idx, StringBuilder sb){
        sb.append(dept+" "); // 방문
        if(idx==n){ // 경로 생성 완료
            list.add(sb.toString());
            return;
        }
        
        for(int i=0;i<n;i++){ // 티켓들 체크
            if(map[i][0].equals(dept) && !visit[i]){ // 다음 티켓 찾음
                visit[i]=true; // 티켓 사용
                dfs(map[i][1], idx+1, sb);
                visit[i]=false; // 사용 안 할 경우
                sb.delete(sb.length()-4, sb.length());
            }
        }
    }
}

3. 결과

실행결과 🤟 성공 🤟
가능한 경우가 여러 개이면 알파벳 순서로 움직여라길래 미리 comparator를 이용하여 sort후 사용하려고 했으나 잘 안됐다.
그리고 dfs 호출 전 visit 여부를 관리해야 하는지, 들어가서 해야 하는지 헷갈린다.

4. 설명

  1. for문을 돌며 시작점을 체크한다
    • ICN인 곳을 찾아서 순회를 시작한다.
    • 해당 티켓을 썼으므로 visit[i]는 true로 바꾸고, dfs()를 이용하여 dest를 다시 dept로 가지는 곳을 찾는다.
    • ICN을 찾았지만 사용하지 않을 수도 있다. 따라서 dfs()후에 false로 처리하여 사용하지 않는다.
    • dfs()를 다 돌고 나면 모든 경우가 list에 저장된다. 이를 알파벳 순 오름차순으로 정렬하면 0번째 값이 정답이다.
  2. DFS
    • 파라미터 dept는 이전에 dest였으므로 sb에 넣는다.
    • idx는 sb에 저장된 갯수로, n개가 되면 모든 곳을 다 방문한 것이므로 list에 넣고 종료한다.
    • 아니라면, tickets를 다시 돌며 다음 티켓을 찾는다.
    • 해당 티켓을 쓸 경우와 아닐 경우를 나눠서 짠다.
    • dfs로 방문 호출하고 난 뒤에 sb에서 삭제해야 한다. for문 밖에서 지우면 지금 위치는 방문하지 않았다는 것인데, 그러면 지금 위치 이전의 출발지는 방문하고 지금 위치는 방문하지 않는다는 모순이 생기기 때문이다.

👏 해결 완료!

참고