알고리즘 {먼데이} 챌린지 시즌1
    • 01
      난이도 맛보기
    • [예시] [문제] 1. 단어장 만들기
      [예시] [해설] 1. 단어장 만들기
      [예시] [문제] 2. 카드 교환하기
      [예시] [해설] 2. 카드 교환하기
    • 02
      1주차 챌린지 수학과 구현
    • [1주차] [문제] 1. 경로의 개수
      [1주차] [해설] 1. 경로의 개수
      [1주차] [문제] 2. 동명이인
      [1주차] [해설] 2. 동명이인
      [1주차] [문제] 3. 최장 맨해튼 거리
      [1주차] [해설] 3. 최장 맨해튼 거리
      [1주차] [문제] 4. 소수 찾기
      [1주차] [해설] 4. 소수 찾기
    • 03
      2주차 챌린지 구현과 문자열
    • [2주차] [문제] 1. 합격자 찾기
      [2주차] [해설] 1. 합격자 찾기
      [2주차] [문제] 2. 문자열 나누기
      [2주차] [해설] 2. 문자열 나누기
      [2주차] [문제] 3. 출석부
      [2주차] [해설] 3. 출석부
      [2주차] [문제] 4. 폭탄 구현하기
      [2주차] [해설] 4. 폭탄 구현하기
    • 04
      3주차 챌린지 그래프 이론
    • [3주차] [문제] 1. 0커플
      [3주차] [해설] 1. 0커플
      [3주차] [문제] 2. 폴더 폰 자판
      [3주차] [해설] 2. 폴더 폰 자판
      [3주차] [문제] 3. 구름이의 여행
      [3주차] [해설] 3. 구름이의 여행
      [3주차] [문제] 4. 순환하는 수로
      [3주차] [해설] 4. 순환하는 수로
    • 05
      4주차 챌린지 동적프로그래밍
    • [4주차] [문제] 1. 체크 카드
      [4주차] [해설] 1. 체크 카드
      [4주차] [문제] 2. 단풍나무
      [4주차] [해설] 2. 단풍나무
      [4주차] [문제] 3. 거리두기
      [4주차] [해설] 3. 거리두기
      [4주차] [문제] 4. 주차 구역 나누기
      [4주차] [해설] 4. 주차 구역 나누기
    • 06
      5주차 챌린지 기출 변형 문제
    • [5주차] [문제] 1. 개미와 진딧물
      [5주차] [해설] 1. 개미와 진딧물
      [5주차] [문제] 2. 모래섬
      [5주차] [해설] 2. 모래섬
      [5주차] [문제] 3. 수 이어 붙이기
      [5주차] [해설] 3. 수 이어 붙이기
      [5주차] [문제] 4. 구슬 게임
      [5주차] [해설] 4. 구슬 게임
    • 07
      6주차 챌린지 기출 변형 문제
    • [6주차] [문제] 1. 7게임
      [6주차] [해설] 1. 7게임
      [6주차] [문제] 2. 제곱암호
      [6주차] [해설] 2. 제곱암호
      [6주차] [문제] 3. 비밀 편지
      [6주차] [해설] 3. 비밀 편지
      [6주차] [문제] 4. 경쟁 배타의 원리
      [6주차] [해설] 4. 경쟁 배타의 원리
    • 08
      7주차 챌린지 실전 모의고사
    • [7주차] [문제] 1. UXUI 디자이너
      [7주차] [해설] 1. UXUI 디자이너
      [7주차] [문제] 2. 퍼져나가는 소문
      [7주차] [해설] 2. 퍼져나가는 소문
      [7주차] [문제] 3. 구름이의 여행 2
      [7주차] [해설] 3. 구름이의 여행 2
      [7주차] [문제] 4. 이상한 미로
      [7주차] [해설] 4. 이상한 미로
    • 09
      8주차 챌린지 실전 모의고사
    • [8주차] [문제] 1. 구름 숫자
      [8주차] [해설] 1. 구름 숫자
      [8주차] [문제] 2. 뒤통수가 따가워
      [8주차] [해설] 2. 뒤통수가 따가워
      [8주차] [문제] 3. 직사각형 만들기
      [8주차] [해설] 3. 직사각형 만들기
      [8주차] [문제] 4. 구름나라 청소하기
      [8주차] [해설] 4. 구름나라 청소하기
    [예시] [해설] 2. 카드 교환하기
    01 난이도 맛보기
    [예시] [해설] 2. 카드 교환하기

    알고리즘 (출제자 Henry)


    • DFS / BFS
    • 정렬


    문제 해설


    문제의 요구 사항을 파악해 봅시다.

    • 불만족도는 어떤 사람의 번호와 그 사람이 들고 있는 카드의 번호 차이의 절댓값
    • 카드 교환이 적절하게 이루어졌을 때, 불만족도 합의 최솟값 구하기

    보통 난이도가 있는 문제들은 어떤 식으로 요구 사항을 구현할 수 있는지가 문제에서 명확하게 주어지지 않는 경우가 많습니다. 이 문제에서도 불만족도 합의 최솟값을 구하라고만 했지, 어떤 식으로 최솟값을 구하는지는 알려주지 않았기 때문에 문제를 푸는 게 쉽지 않을 것임을 짐작할 수 있습니다. 이런 문제일수록 관찰을 통해 문제를 하나하나 파헤치는 것이 중요합니다.


    카드를 교환할 수 있는 쌍 찾기


    우선 가장 먼저 할 수 있는 일은 주어진 상황을 그래프로 나타내는 것입니다. 어떤 두 정점이나 상태 간의 관계가 주어진다면, 이를 그래프로 나타내보면 좋은 정보를 얻을 수 있는 경우가 많습니다. 이 문제에서는 사람을 정점으로 하고, 친구 관계에 있는 두 사람을 간선으로 하는 그래프로 나타내줄 수 있습니다.

    이제 어떤 사람들끼리 카드를 교환할 수 있을지를 관찰해 봅시다. 우선 그래프 상에서 어떤 두 사람을 연결하는 경로가 존재하기만 한다면 두 사람은 카드를 교환할 수 있습니다. 그 경로를 따라서 사람들이 연속적으로 카드를 교환해 나간다면 이 사실이 성립함을 직관적으로 알 수 있습니다. 추가로 경로 상에 있는 다른 사람들이 들고 있는 카드도 변하지 않으므로, 간선으로 직접적으로 이어져 있지 않더라도 연결만 되어 있다면 카드를 교환할 수 있습니다. 

    같은 연결 컴포넌트에 있는 사람들끼리는 마음대로 카드를 교환할 수 있다는 사실을 알았으므로, 그 컴포넌트에 속한 사람들의 카드를 아무렇게나 섞은 다음 다시 나눠준다고 생각해도 무방합니다.


    최적의 카드 배분 찾기


    그러면 어떻게 카드를 나눠주는 것이 최적일까요? 어떤 컴포넌트에 두 명의 사람이 속해 있고, 각 사람의 번호가 라고 합시다. 그러면 와의 대소 관계에 따라 아래 여섯 가지 경우로 나뉘게 되고, 최적으로 카드를 배분해주는 경우는 검은색 점선과 같습니다. 회색 점선은 최적이 아닌 경우를 의미합니다. (그림을 클릭하면 더 선명하게 볼 수 있습니다.)

    default

    이 그림을 통해 알 수 있는 사실은, 카드를 배분하는 최적의 경우에서는 항상 점선이 교차하지 않는다는 점입니다. 이 성질은 임의의 두 쌍에 대해서 항상 성립하므로, 따라서 컴포넌트에 속한 사람의 수가 두 명보다 더 많더라도 점선이 교차하지 않는 배분 방식이 곧 최적임을 알 수 있습니다. 설명이 다소 직관적으로 이루어졌지만, Exchange Argument를 이용하면 위 직관이 성립함을 증명할 수 있습니다.

    점선이 교차하지 않도록 카드를 배분하는 방법은 사람들의 번호와 카드의 번호를 정렬한 뒤, 순서대로 배분해주는 것으로 가능합니다.

    이상의 내용을 정리해보면, 다음과 같은 순서로 문제를 해결할 수 있습니다.

    1. 주어진 친구 관계를 그래프로 나타낸다.
    2. 같은 연결 컴포넌트에 속한 사람들을 찾는다.
    3. 카드 번호와 사람들의 번호를 각각 정렬한 뒤, 정렬된 순서대로 카드를 배분한다.

    그래프를 탐색하는 데 , 답을 계산하는데  시간이 걸리므로 총 시간복잡도는  입니다.


    주의사항


    주어진 예제와 같이 연결 컴포넌트가 여러 개일 수 있습니다. 그리고 답이 32-Bit 정수 범위를 넘어갈 수 있으니, 64-Bit 정수 자료형을 이용해 문제를 해결해야 합니다.

    추가로 스택 메모리 제한으로 인해, C++ 이외의 언어에서는 DFS를 이용해 연결 컴포넌트를 탐색하면 Stack Overflow가 일어날 수 있습니다. 아래 Python 정해 코드와 같이 BFS 또는 Union-Find를 이용하면 에러 없이 문제를 잘 해결 가능합니다.


    코드(Python/C++)


    py3
    cpp
    질문하기