본문 바로가기
PS/BOJ

[자바] 백준 1375 - 나이 (java)

by Nahwasa 2023. 12. 14.

문제 : boj1375

 

 

필요 알고리즘

  • 그래프 탐색(bfs, dfs), 값/좌표 압축
    • 값/좌표 압축이야 그냥 String을 쓰기 편하게 int로 바꾼 것 뿐이고, 풀이는 그냥 bfs를 썼다. 의외로 별다른 것 없이 bfs나 dfs로 풀 수 있다.

※ 제 코드에서 왜 main 함수에 로직을 직접 작성하지 않았는지, 왜 Scanner를 쓰지 않고 BufferedReader를 사용했는지 등에 대해서는 '자바로 백준 풀 때의 팁 및 주의점' 글을 참고해주세요. 백준을 자바로 풀어보려고 시작하시는 분이나, 백준에서 자바로 풀 때의 팁을 원하시는 분들도 보시는걸 추천드립니다.

 

 

풀이

  우선 입력이 String으로 들어오는데 이 부분부터 처리해보자. 그냥 새로운 문자열이 들어오면 그걸 새로운 int로 바꿔주면 된다. 어차피 해당 값은 n이상이 될 수 없으므로 최대 N개의 String이 최대 N인 int로 변환될 뿐이다. 아무래도 정점 번호는 int인게 이후 처리하기 편하다.

if (!comp.containsKey(a)) comp.put(a, num++);
if (!comp.containsKey(b)) comp.put(b, num++);

 

 

  그럼 이 문제는 그냥 N개의 정점에 대해 어떤 쪽이 나이가 많은지에 대한 정보가 주어지고, Q개의 질문으로 어느쪽이 나이가 많은지 알려주면 되는 문제이다.

 

  여기서 어느 쪽이 나이가 많은지에 대한 정보를 간선이라고 생각해보자. 즉 'a b'형태의 입력에 대해 a에서 b로 향하는 단방향 간선을 그어준다고 생각해보자. 이후 Q개의 질문에 대해 a와 b가 주어졌다. a에서 그래프 탐색을 시작하는 중간에 b를 만났다면 그게 뭘 의미할까? a가 b보다 더 나이가 많은질 뜻한다. 반대로 b에서 탐색해서 a가 도달 가능하다면 b가 나이가 많은거다. a->b 혹은 b->a 둘 다 불가하다면 gg 치면 된다.

if (reachable(numA, numB)) sb.append(a).append(' ');
else if (reachable(numB, numA)) sb.append(b).append(' ');
else sb.append("gg ");

 

 

  여기서 문제가 될거라 생각한 부분은 문제에 "모슨되는 데이터는 없습니다." 라는 내용이 없었다는 점이다. 즉, 입력이 '1 2', '2 1' 처럼 모순되는 내용이 있다면 이하 코드만으론 풀 수 없어서 사이클 판정까지 해야해서 좀 까다로워 진다. 그건 일단 제출해보고 틀리면 생각하려고 했는데 그냥 통과했다. 결론적으로 왜 골2인진 잘 모르겠다. 아마 나이에 대한 정보를 간선으로 변경한다는 아이디어 때문일꺼라 생각된다.

 

 

코드 : github

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

public class Main {
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in), 1 << 16);

    public static void main(String[] args) throws Exception {
        new Main().solution();
    }

    int n;
    List<Integer>[] edges;

    public void solution() throws Exception {
        StringTokenizer st = new StringTokenizer(br.readLine());
        n = Integer.parseInt(st.nextToken());
        int m = Integer.parseInt(st.nextToken());

        int num = 0;
        Map<String, Integer> comp = new HashMap<>();
        edges = new List[n];
        for (int i = 0; i < n; i++) edges[i] = new ArrayList<>();
        while (m-->0) {
            st = new StringTokenizer(br.readLine());
            String a = st.nextToken();
            String b = st.nextToken();
            if (!comp.containsKey(a)) comp.put(a, num++);
            if (!comp.containsKey(b)) comp.put(b, num++);
            edges[comp.get(a)].add(comp.get(b));
        }

        int q = Integer.parseInt(br.readLine());
        StringBuilder sb = new StringBuilder();
        while (q-->0) {
            st = new StringTokenizer(br.readLine());
            String a = st.nextToken();
            String b = st.nextToken();
            int numA = comp.getOrDefault(a, -1);
            int numB = comp.getOrDefault(b, -1);
            if (numA == -1 || numB == -1) {
                sb.append("gg ");
                continue;
            }

            if (reachable(numA, numB)) sb.append(a).append(' ');
            else if (reachable(numB, numA)) sb.append(b).append(' ');
            else sb.append("gg ");
        }
        System.out.println(sb);
    }

    private boolean reachable(final int a, final int b) {
        boolean[] v = new boolean[n];
        v[a] = true;
        Queue<Integer> q = new ArrayDeque<>();
        q.add(a);

        while (!q.isEmpty()) {
            int cur = q.poll();
            for (int next : edges[cur]) {
                if (next == b) return true;

                if (v[next]) continue;
                v[next] = true;
                q.add(next);
            }
        }

        return false;
    }
}

 

댓글