1238번 파티 문제 풀러 가기

 

1238번: 파티

첫째 줄에 N(1 ≤ N ≤ 1,000), M(1 ≤ M ≤ 10,000), X가 공백으로 구분되어 입력된다. 두 번째 줄부터 M+1번째 줄까지 i번째 도로의 시작점, 끝점, 그리고 이 도로를 지나는데 필요한 소요시간 Ti가 들어

www.acmicpc.net

 

 

1. 문제 분석


  • N명의 학생들은 X번 마을까지 갔다가 다시 돌아와야 한다.
  • 이때 갔다가 다시 돌아오는 최단 거리를 구해야 한다.
  • 각 마을에서 마을로 이동하는 데는 양의 가중치(거리)가 존재한다.

 

 

 

2. 생각해 보기


  • 양의 가중치가 존재하기 때문에 다익스트라 아니면 플로이드 와샬을 고려해 본다.
  • 플로이드 와샬 알고리즘은 O(N^3)의 시간 복잡도가 필요하다. 마을의 개수(N)가 최대 10^3이기 때문에 플로이드 와샬을 사용하면 최대 10^9의 시간이 걸릴 수 있어 시간 초과가 날 가능성이 있다.
  • 그럼 고려해 볼 수 있는 알고리즘은 다익스트라 알고리즘이다.
  • 다음은 각 마을에서 X로 가는 최단 거리와, X에서 다시 각 마을로 돌아가는 최단 거리를 구해야 한다.
  • 그대로 구현한다면 1, 3, 4 마을에서 각각 2번 마을까지 갈 수 있는 거리를 구해야 한다. 이를 반대로 생각해 보면 다음과 같이 접근해 볼 수 있다.
     
    1. (시작 마을) (끝 마을) (거리)를 입력받을 때, 입력받은 대로 저장하는 경우 map과 (끝 마을) (시작 마을) (거리)로 저장하는 경우reverseMap을 모두 저장한다.
    2. X 마을에서 각 마을(1, 3, 4)로 돌아가는 경우를 구할 때는 map을 사용하면 X 마을을 시작점으로 각 마을로 돌아가는 거리를 구할 수 있다.
    3. 각 마을(1, 3, 4)에서 X 마을로 가는 경우를 구할 때는 reverseMap을 사용하면 X 마을을 시작점으로 각 마을로 가는 거리를 구할 수 있다.
    4. 이렇게 reverseMap을 사용하면 X 마을이 도착점이 아닌 시작 마을로 해서 간단하게 다익스트라 알고리즘을 2번 돌려주면 원하는 값을 얻을 수 있다.

 

 

 

3. 소스코드


import java.io.*;
import java.util.*;

public class Main {
    static int N, M, X;
    static List<Node>[] map, reverseMap; // 인접 리스트로 저장

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        N = Integer.parseInt(st.nextToken());
        M = Integer.parseInt(st.nextToken());
        X = Integer.parseInt(st.nextToken());
        map = new ArrayList[N + 1];
        reverseMap = new ArrayList[N + 1];

        for (int i = 1; i <= N; i++) {
            map[i] = new ArrayList<>();
            reverseMap[i] = new ArrayList<>();
        }

        for (int i = 0; i < M; i++) {
            st = new StringTokenizer(br.readLine());
            int start = Integer.parseInt(st.nextToken());
            int end = Integer.parseInt(st.nextToken());
            int dist = Integer.parseInt(st.nextToken());
            map[start].add(new Node(end, dist));
            reverseMap[end].add(new Node(start, dist));
        }
        int[] go = dijkstra(reverseMap); // 각 노드에서 X로 가는 최단 경로
        int[] back = dijkstra(map); // X에서 각 노드로 가는 최단 경로

        int answer = 0;
        for (int i = 1; i <= N; i++) {
            answer = Math.max(answer, go[i] + back[i]);
        }
        System.out.println(answer);
    }

    public static int[] dijkstra(List<Node>[] inputMap) {
        boolean[] visited = new boolean[N + 1];
        int[] result = new int[N + 1];
        Arrays.fill(result, Integer.MAX_VALUE);
        result[X] = 0; // X에서 X로 가는 경로는 0으로 초기화

        // 다익스트라 알고리즘 시작
        PriorityQueue<Node> queue = new PriorityQueue<>((n1, n2) -> n1.dist - n2.dist);
        queue.add(new Node(X, 0));

        while (!queue.isEmpty()) {
            Node curr = queue.poll();
            if (visited[curr.end]) {
                continue;
            }
            visited[curr.end] = true;
            for (Node node : inputMap[curr.end]) {
                if (curr.dist + node.dist < result[node.end]) {
                    result[node.end] = curr.dist + node.dist;
                }
                queue.add(new Node(node.end, result[node.end]));
            }
        }
        return result;
    }

    static class Node {
        int end, dist;

        public Node (int end, int dist) {
            this.end = end;
            this.dist = dist;
        }
    }
}
  • 저는 다익스트라 알고리즘에 사용될 map과 reverseMap을 인접리스트 형식으로 저장했습니다.
  • PriorityQueue를 사용해서 Node의 dist(거리)를 기준으로 오름차순 정렬되도록 선언했습니다.
  • 거리 기준 오름차순으로 저장하면 해당 노드로 도달할 수 있는 최단 거리를 얻을 수 있고, 같은 노드에 대한 정보가 나중에 들어오면 visited를 통해서 contitnue로 걸러줬습니다.

 

 

 

4. 알게 된 점


  • 그래프에서 어떤 특정 노드까지 이동을 하고, 다시 되돌아와야 하는 경우가 존재한다면, 해당 특정 노드를 시작점으로 해결해 볼 수 있다는 것을 알게 되었습니다. (입력을 거꾸로 저장, reverseMap)

1. PDU (Protocol Data Unit)이란?


  • 네트워크의 계층과 계층 사이에 데이터가 전달될 때 한 덩어리의 단위를 PDU라고 합니다.
  • PDU는 헤더와 페이로드로 구성되어 있고, 계층마다 부르는 명칭이 다릅니다.

계충 별로 불리는 PDU 명칭

 

(1) 헤더 (Header)

  • 각 계층마다 필요한 정보 및 기능이 담겨있습니다.
  • 제어 관련 정보들이 포함되어 있습니다.
  • (송신) 상위 계층에서 전달된 PDU에 자신의 계층에서 만든 헤더를 추가해서 하위 계층으로 전달합니다.
  • (수신) 각 층에서 생성한 헤더 정보는 각 층에서 해결합니다.

 

 

(2) 페이로드 (Payload)

  • 송신 측에서 보내고자 하는 실제 데이터를 의미합니다.
  • 택배를 예로 들면 박스, 송장, 포장지 등은 페이로드에 속하지 않고, 받기로 한 택배물이 페이로드라고 생각하면 됩니다.

1. 네트워크 프로토콜이란?


  • 다른 장치들끼리 데이터를 주고받기 위해 설정된 공통된 인터페이스를 말합니다.
  • 쉽게 생각해 보면 장치와 장치 사이에 데이터 통신을 해야 하는데, 미리 정해놓은 어떤 규약(약속)에 따라서 통신을 하게 됩니다. 이때 이 규약(약속)을 네트워크 프로토콜이라고 합니다.

 

 

 

2. 프로토콜의 표준화가 필요한 이유?


  • 모든 송신자와 모든 수신자가 표준화된 프로토콜을 지키기만 한다면 서로 통신이 가능하도록 해줍니다.
  • 하지만 프로토콜이 표준화되어 있지 않다면, 특정 송신자는 자신의 프로토콜과 일치한 특정 수신자에게만 데이터를 송신할 수 있게 됩니다.

 

 

 

3. 프로토콜의 종류


  • 많이 들어본 프로토콜 위주로 정리해보면 TCP, IP, UDP, HTTP 등이 있습니다. 여기서 마지막에 붙은 'P'가 Protocol의 약자입니다.

 

 

(1) TCP (Transmission Control Protocol)

  • OSI 참조 모델 4계층의 전송 계층에서 사용되는 네트워크 프로토콜입니다.
  • TCP는 데이터의 손실이 없이 확실하게 상대방에게 전송하기 때문에 신뢰성이 높은 프로토콜입니다. (수신 확인을 진행)
  • 현재는 TCP와 IP를 조합한 TCP/IP 프로토콜이 사용되고 있습니다.

 

 

(2) IP (Internet Protocol)

  • OSI 참조 모델의 3 계층인 네트워크 계층에서 사용되는 네트워크 프로토콜입니다.
  • 각 장치(기기)에 주소를 할당하고 경로를 선택하여 데이터를 전송하기 위해 사용되는 프로토콜입니다.
  • 상위 계층에서 패킷을 보내주면, 패킷을 수신한 뒤에 IP 헤더를 추가하여 네트워크에 전송하게 됩니다.
  • IP 헤더에는 보내는 사람(수신자)의 IP 주소, 받는 사람(송신자)의 IP 주소와 같은 정보들이 모여있고, 이 정보를 가지고 경로를 선택하여 물통 릴레이 방식으로 목적지로 패킷이 전달됩니다.

 

 

(3) UDP (User Datagram Protocol)

  • TCP와 마찬가지로 OSI 참조 모델 4 계층의 전송 계층에서 사용되는 네트워크 프로토콜입니다.
  • TCP에서는 신뢰성을 확보하기 위해서 송신 측은 수신 측에 패킷이 정상적으로 도달했는지 확인을 진행합니다.
  • UDP에서는 단순히 패킷을 보내기만 할 뿐 수신측에 패킷이 정상적으로 도달했는지 확인하지 않습니다.
  • 도중에 패킷이 분신되어도 알 수 있는 방법이 없어 신뢰성은 떨어지지만 처리가 가벼워서 속도가 빠르다는 장점이 있습니다.
  • 동영상과 같이 도중에 일부가 끊어지는 것보다는 실시간으로 전송되는 것이 중요한 경우에 유용하게 사용될 수 있는 프로토콜입니다.

 

 

(4) HTTP (Hyper Text Transfer Protocol)

  • WWW 클라이언트(웹 브라우저)와 WWW 서버 사이의 통신에 사용되는 네트워크 프로토콜입니다.
  • 웹 브라우저에서 요청이 들어오면 WWW 서버는 응답하는 방식으로 작동되는 간단한 프로토콜입니다.
  • 일반적인 통신 포트는 80번 포트를 사용합니다.

 

 

 

💡 면접에서 나올 수 있는 질문

  1. 네트워크 프로토콜이 무엇인가요?
  2. 네트워크 프로토콜의 표준화가 필요한 이유에 대해서 설명해 보세요.
  3. TCP와 UDP을 비교하여 설명해 보세요.

 

'📘 Computer Science > 네트워크' 카테고리의 다른 글

[네트워크] HTTPS와 SSL/TLS  (0) 2023.06.22
[네트워크] PDU (Protocol Data Unit)  (0) 2023.06.03

1. 중첩 루프 조인 (NLJ, Nested Loop Join)


  • 중첩 for 문과 같은 원리로 조건에 맞는 조인을 하는 방법을 말합니다.
  • Index에 의한 Random Access 비용이 많이 증가하기 때문에 대용량 데이터를 다루기에는 적절하지 않습니다.

 

중첩 루프 조인의 작동

# CS 전공지식 노트 226 page

for each row in t1 matching reference key {
    for each row in t2 matching reference key {
        if row satisfies join conditions, send to client
    }
}
  • 위에 있는 코드는 중첩 루프 조인을 사용하여 t1 테이블과 t2 테이블을 조인하는 의사 코드입니다.
  • t1 테이블에서 행을 한 번에 하나씩 읽고, t2 테이블에서도 행을 하나씩 읽으며 조건에 맞는 데이터를 찾아서 반환하게 됩니다.
  • 여기서 t1을 Driving Table이라고 하며, t2를 Driven Table이라고 합니다. 
  • 중첩 루프 조인에서는 Driving Table을 적절하게 선택해야 합니다. 처음 Driving Table에 해당되는 row가 너무 많다면, 그만큼의 반복을 해줘야하기 때문에 Driving Table에서 Where절로 row 수를 최대한 줄일 수 있어야 합니다.
  • Driving Table의 Join Column에 index가 존재하는지도 확인해봐야 합니다. 존재하지 않는다면 Random Access가 아닌 Full Table Scan을 통해서 모두 비교해야 하기 때문에 index를 생성하는 것이 좋습니다.

 

[출처]&nbsp;https://dataonair.or.kr/db-tech-reference/d-guide/sql/?mod=document&uid=356

 

* Driving Table : Join 할 때, 먼저 Access되어 Access Path를 주도하는 테이블
* Driven Table : Join 할 때, 나중에 Access되는 테이블

 

 

 

2. 정렬 병합 조인 (Sort Merge Join)


  • 각각의 테이블을 조인할 필드 기준으로 정렬한 후 조인 작업을 수행하는 조인 방법입니다.
  • 조인할 때 사용할 적절한 인덱스가 존재하지 않고, 대용량 테이블을 조인하는 데 사용됩니다.
  • 조인 조건으로 비교 연산자(>, <, >=, <=)가 있을 때도 사용됩니다.
  • 조회 범위가 좁을 때 유리했던 Nested Loop Join과는 다르게 조회 범위가 많을 때 주로 선택되어 사용합니다.

 

정렬 병합 조인의 작동

  • 각 테이블에 대해서 독립적으로 데이터를 읽어옵니다. 인덱스가 존재하는 컬럼의 테이블은 Random Access, 인덱스가 존재하지 않는 컬럼의 테이블은 Full Table Scan을 사용합니다.
  • 읽힌 각 테이블의 데이터를 조인을 위한 연결고리에 대하여 정렬을 수행합니다.
  • 정렬이 모두 끝난 뒤 정렬된 데이터를 차례로 Scan 하면서 연결고리의 조건으로 Merge하여 데이터를 반환합니다.

 

[출처]&nbsp;https://dataonair.or.kr/db-tech-reference/d-guide/sql/?mod=document&uid=356

 

 

 

3. 해시 조인 (Hash Join)


  • 조인할 두 테이블 중 하나를 해시 테이블로 선정하여 조인에 사용되는 컬럼 값을 해시 알고리즘으로 비교하여 조인하는 방법입니다.
  • 동등(=) 조인에서만 사용할 수 있습니다.
  • Sort Merge Join을 할 때, 테이블 크기가 너무 커서 Sort에 드는 부하가 너무 클 때 해시 조인가 사용됩니다.
  • 조인에 사용되는 컬럼에 적절한 index가 존재하지 않아서 Nested Loop Join을 사용하기에 효율적이지 못할 때 사용됩니다.

 

해시 조인의 작동

  • A 테이블과 B 테이블을 조인할 때, 둘 중 바이트가 더 작은 테이블을 읽어서 Hash Area에 해시 테이블을 생성합니다. 이때 해시 테이블의 Key는 조인에 사용되는 필드가 됩니다.
  • 만약 A 테이블이 해시 테이블로 생성되었다면, A 테이블은 Build Input이라고 하고, B 테이블은 Probe Input이라고 합니다.
  • B 테이블을 스캔하며 조인 컬럼을 해시 함수에 넣고, 반환되는 버킷 주소로 찾아가 해시 체인을 스캔하며 Join 할 데이터를 찾아서 반환합니다.

 

[출처]&nbsp;https://dataonair.or.kr/db-tech-reference/d-guide/sql/?mod=document&uid=356

 

 

 

💡 나올 수 있는 질문

  1. 중첩 루프 조인(Nested Loop Join)에 대해서 설명해보세요.

 

백준 문제를 IDE로 풀고 있었는데, 사소한 오타로 계속 시간을 허비하게 되어서 인텔리제이 설정을 하면서 기록해 두려고 이 글을 작성합니다.

 

발생했던 휴먼에러는 i와 j를 구분하지 못했던 것. i와 j 밑에 밑줄이 그어지니깐 구분을 못하겠어서 불편해 죽겠다.

 

이건 아마도 Material Dark 테마를 설정하고 있는 사람만 해당될 문제라고 생각된다.

 

뭐가 i이고, 뭐가 j인지 거북목 생길 거 같다.

 

위 사진처럼 확대하면 구분할 수 있을거 같지만 작은 글씨로 보면 i와 j 밑에 밑줄이 있으면 구분을 못하겠다. j를 써야 할 자리에 자꾸 i를 쓴다던가 하는 오류를 줄이기 위해서 밑줄을 없애버리자.

 

 

설정하기

  • 설정창을 열기 위해서 command + , 을 눌러 준다.
  • 검색창에 "color scheme" 검색
  • Langauge Defaults -> Identifiers -> Reassigned local variable 선택
  • Effects 체크 풀어주기
  • Apply 후 저장

한 눈에 보는 설정 방법

 

이제 다시 에디터를 보면 지역변수에 밑줄이 사라진 것을 볼 수 있다. 편 - 안

밑줄이 제거된 모습

 

1. 관계형 데이터베이스 (RDBMS)


  • 행과 열로 구성된 표 형식 데이터를 저장하는 데이터베이스입니다.
  • SQL이라는 언어를 써서 조작할 수 있습니다.
  • 관계형 데이터베이스의 종류에는 MySQL, Oracle, PostgreSQL, MSSQL 등이 있습니다.
  • 관계형 데이터베이스는 표준 SQL을 지키기는 하지만 각 제품에서 특화시킨 SQL을 사용합니다.

 

(1) MySQL

  • 세계에서 가장 많이 사용되고 있는 오픈소스 관계형 데이터베이스입니다.
  • MySQL의 최고 장점은 오픈소스이기 때문에 무료라는 것입니다.
  • 문자열 비교에 있어서 대소문자를 구분하지 않습니다. BINARY 설정 등을 이용하면 추가 설정이 가능합니다.
  • nested loop join만을 제공한다는 단점이 있습니다. MySQL 8.0.18 릴리스 버전 이후로는 hash join도 제공하게 되었습니다.
nested loop join (중첩 루프 조인)
: 바깥 테이블의 처리 범위를 하나씩 접근하며 추출된 값으로 안쪽 테이블을 조인하는 방법입니다.
중첩 for문과 비슷한 동일한 원리라고 생각하면 됩니다. 비용이 많이 들어서 대용량 테이블에서는 사용하지 않습니다.

hash Join (해시 조인)
: 해시 테이블을 기반으로 조인하는 방법을 말합니다. 2개의 테이블을 조인할 때, 하나의 테이블을 해시 테이블로서 사용합니다.
동등(=) 조인에서만 사용이 가능하고, 테이블의 크기가 너무 크다면 디스크를 사용하는 비용이 증가할 수 있습니다.

 

 

(2) Oracle DB

  • Oracle 사에서 만든 관계형 데이터베이스입니다.
  • MySQL, MSSQL 보다 대용량 정보를 관리할 때 성능이 좋습니다.
  • 고성능 트랜잭션 처리를 제공하여 속도가 빠릅니다.
  • SQL문을 실행하는 가장 효율적인 방법을 제공합니다. 쿼리비용 최소화를 위해서 테이블 인덱싱 분석을 합니다.
  • 과거 시점의 데이터 조회도 가능하고, 커밋 이전의 상태로 되돌릴 수 있는 기능이 존재합니다.
  • 메모리를 너무 많이 차지하기 때문에 고사양 장비가 요구된다는 단점이 있습니다.

 

 

(3) PostgreSQL

  • 다양한 Join 방법을 제공합니다. (nested loop join, hash join, sort merge join)
  • update 시에는 기존에 있던 행을 지우고, 변경된 데이터를 가지는 새로운 행을 추가하는 방식을 사용하여 update 성능은 비교적 좋지 않습니다.
  • 데이터베이스 클러스터 백업 기능을 제공합니다.
  • hot backup과 wal replay를 활용하여 원하는 시점의 데이터 복구가 가능합니다.
  • SQL 뿐만 아니라 JSON을 이용해서도 데이터에 접근할 수 있습니다.
sort merge join (정렬 병합 조인)
: 각각의 테이블에서 조인할 필드 기준으로 정렬한 후 조인 작업을 수행하는 조인방법입니다.

hot backup
: 데이터베이스가 실행 중인 상태에서 데이터를 백업받는 방식입니다. 

 

(4) MSSQL

  • 마이크로소프트 사에서 사이베이스(Sybase)를 기반으로 개발한 관계형 데이터베이스입니다.
  • 윈도우 개발환경에서 DB가 필요할 경우 MSSQL을 사용합니다.
  • windows 기반 서버에서만 작동되도록 설계되어 있고, 라이센스 비용이 비싸다는 단점이 있습니다.
  • 하지만 우수한 데이터 복구 지원을 제공한다는 장점이 존재합니다.

 

 

 

2. NoSQL 데이터베이스


  • SQL를 사용하지 않는 데이터베이스를 말합니다.
  • 대표적으로 알려진 NoSQL 데이터베이스는 MongoDB와 Redis가 존재합니다.

 

(1) MongoDB

  • JSON을 통해서 데이터에 접근할 수 있습니다.
  • 데이터가 저장될 때는 Binary JSON 형태로 데이터가 저장되며 도큐먼트 기반의 데이터베이스입니다.
  • 확장성이 뛰어나고, 빅데이터를 저장할 때 성능이 좋습니다.
  • 스키마를 정해 놓지 않고 데이터를 삽입하기 때문에 다양한 도메인의 데이터베이스를 기반으로 분석할 수 있습니다.
  • 도큐먼트를 생성할 때마다 다른 컬렉션과 구별하기 위해서 유니크한 ObjectId가 생성됩니다.

[출처] CS 전공지식 노트 p.216

 

(2) Redis

  • 인메모리 데이터베이스이며, Key-Value 데이터 모델 기반의 데이터베이스입니다.
  • 다른 데이터베이스를 앞단에 두어 사용하는 캐싱 계층으로 사용됩니다.
  • 기본적인 데이터 타입은 문자열이며 최대 512MB까지 저장할 수 있습니다. 이외에도 Set과 Hash 등을 지원합니다.

 

 

 

🔗 참고 자료

주요 RDBMS의 종류

면접을 위한 CS 전공지식 노트

+ Recent posts