alorithm/Baekjoon

[백준] 2644번: 촌수계산

Hannana. 2024. 8. 13. 02:22
728x90
반응형

https://www.acmicpc.net/problem/2644

 

 

 

문제 파악

-총 노드 갯수 n

-특정 노드 a,b (a: start, b: target)

-간선 m

-~연결관계~ : 단방향(부모-자식 관계 명확)

*StringTokenizer는 문자열 한 줄에서만 유효, 여러 줄일 시 새로운 st 선언해줘야 한다. 

*또한 띄어쓰기가 있는 문자열 쪼개는 데 쓴다.

*br.readLine으로 받아서 해당 String.charAt()으로 받는 건 띄어쓰기가 없을 경우에 사용!

 

접근 방법

-BFS함수 별도 작성

-시작점a로부터 도착노드b까지 top-bottom이 명확한 그래프이지만, 위로 거슬러 올라가는 로직을 별도로 추가하여

4방향 탐색하듯이 (경우 따져보고 전진), 

가능하면 전진하여 카운트하고 아니면 그 다음 경우로 부모까지 순회하여 큐에 모두 순서대로 담아준다.

-부모로 가든, 자식으로 가든 1노드씩 전진하므로 레벨을 잘 카운트해서 레벨 증가시키며 리스트에 담아주기

-만약, target을 찾으면 카운트 한 레벨 값을 리턴하고, 못찾으면 -1

-못찾았다 = 다른 네트워크에 있다. 다른 그래프다. 공통 조상 없다. 닿을 수 없는 남이다. 😂

 

코드 구현

package baekjoon;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;

public class p2644_촌수계산 {
    public void 촌수계산() throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        int n=Integer.parseInt(br.readLine());
        StringTokenizer st = new StringTokenizer(br.readLine());
        int a=Integer.parseInt(st.nextToken());
        int b=Integer.parseInt(st.nextToken());
        int m=Integer.parseInt(br.readLine());//간선 갯수=관계 갯수
        Map<Integer, List<Integer>> map = new HashMap<>();
        Map<Integer, List<Integer>> reverseMap = new HashMap<>(); // 부모-자식 관계를 역으로 저장하는 맵

        for(int i=0;i<m;i++){
            st = new StringTokenizer(br.readLine());
            int parent=Integer.parseInt(st.nextToken());
            int child=Integer.parseInt(st.nextToken());
            map.putIfAbsent(parent,new ArrayList<>());
            map.get(parent).add(child);
            // 자식에서 부모로의 관계도 추가
            reverseMap.putIfAbsent(child, new ArrayList<>());
            reverseMap.get(child).add(parent);
        }
        int distance = bfs(a,b,n,map,reverseMap);
        System.out.println(distance);
    }

    public int bfs(int start,int target,int n,Map<Integer,List<Integer>> map,Map<Integer,List<Integer>> reverseMap){
        Queue<Integer> que=new ArrayDeque<>();
        boolean[] visited = new boolean[n+1];
        Map<Integer, Integer> levelMap = new HashMap<>();

        que.offer(start);
        visited[start]=true;
        levelMap.put(start,0);
        while(!que.isEmpty()){
            int node=que.poll();
            int level=levelMap.get(node);
            if(node==target){
                return level;
            }
            //level=result.get(node); //result.get(node)+1 노드(이전 레벨)이 기록 된 레벨 불러와 +1
            //map.get(node)가 null이면 nullPointException 발생 가능성 있음
            List<Integer> temp = map.getOrDefault(node, new ArrayList<>());
            for(int i:temp){
                if(!visited[i]){
                    que.add(i);
                    visited[i]=true;
                    levelMap.put(i,level+1);
                }
            }//해당 노드의 자식 먼저 순회하고,
            List<Integer> toParent = reverseMap.getOrDefault(node, new ArrayList<>());
            for(int i:toParent){
                if(!visited[i]){
                    que.add(i);
                    visited[i]=true;
                    levelMap.put(i,level+1);
                }
            }//해당 노드의 부모까지 순회한다.
        }

        return -1;
    }
}

배우게 된 점

-일단 빨리 찾으면 이득이니 BFS로 찾고

-처음엔, 방향성이 명확하여 공통 조상을 찾아, top-down 방식으로 순회하는 방식으로 코드를 짰지만

nullPointError가 자꾸 발생했고, 정확한 답이 나오지 않아서 통과를 못했다.

-방식을 바꿔 자식에서 부모로 거슬러 올라가는 로직을 추가함

-처음 보는 유형이라 생각하기까지가 어려웠다.

 

 

 

 

반응형

'alorithm > Baekjoon' 카테고리의 다른 글

[백준] 미로 탐색  (0) 2024.08.13
[백준] 2667번: 단지번호붙이기  (0) 2024.08.13
[Python/백준] 23791번 : ZOAC 4  (0) 2024.06.17
[JAVA/백준] 2343번 : 기타 레슨  (0) 2023.11.08
[JAVA/백준] 1920번 : 수 찾기  (0) 2023.11.06