티스토리 뷰

문제 링크


D. Happy Number


문제에 적혀 있는 함수 $f$가 있다. $f(f(f(...f(n))))$을 했을 때, 1이 되는지를 구하는 문제다.

입력으로 주어지는 수는 최대 1,000,000,000인데, 큰 수가 주어진다하더라도 $f(n)$의 결과값은 작다. 때문에 이 문제는 함수 $f$를 구현하고 결과값이 1이 되는지만 확인하는 간단한 문제가 된다.


코드 보기


C. Game Map


N개의 정점과 M개의 간선으로 이루어진 무방향성 그래프가 주어진다. 임의의 정점에서 시작하여 방문하는 정점의 차수(degree)가 증가하도록 이동하는 경로 중에서 가장 긴 경로의 길이를 구하는 문제다.

아래와 같은 DP배열을 생각하자.

D[i] = 임의의 시작점에서 정점 i까지 오는 경로 중에서 가장 긴 경로의 길이.

차수가 낮은 정점부터 차례대로 DP 값을 뿌려주거나, DP 값을 계산하면 올바르게 DP 값을 구할 수 있다.

정점을 차수 순서대로 정렬해야하므로, 시간복잡도는 $O(N \lg N + M)$이 된다.


코드 보기


F. Philosopher's Walk


문제에서 주어진 그림처럼 재귀적으로 문양을 그린다. 문양의 크기 n과 순서 m이 주어졌을 때, 문양을 그리면서 m번째로 방문한 칸의 좌표를 구하는 문제다.

이 문제는 문양을 직접 2차원 배열에 그리지 않되, 재귀함수를 잘 짜서 문양을 그리는 로직을 작성하면 해결할 수 있다. 재귀함수의 구성이나, 자세한 테크닉은 코드를 참고하자. 시간복잡도는 $O(\lg N)$이다.


코드 보기


H. Rock Paper Scissors


길이가 N인 가위바위보 문자열과 길이가 M인 가위바위보 문자열이 주어진다. 길이가 M인 가위바위보 문자열을 원하는 시점에서 시작하여, 최대한 많은 승수를 쌓는 문제다. 길이가 M인 가위바위보 문자열이 오른쪽으로 삐져나가도 괜찮다.

길이가 N인 가위바위보 문자열의 각 문자를 이기는 문자로 바꾼다. 즉, 'R'은 'P'로, 'P'는 'S'로, 'S'는 'R'로 바꾼다. 그러면 이제 문제는 길이가 N인 전체 문자열이 있고, 길이가 M인 패턴 문자열이 있고, 패턴과 가장 많은 문자가 겹치는 순간을 찾는 문제가 된다.

문자의 종류수가 3 종류라는 것을 감안했을 때, FFT를 이용하여 각 문자 종류마다 패턴이 어느 위치에 갔을 때 겹치는 칸의 수를 구할 수 있다. 이를 합산하면 문제가 해결된다. 시간복잡도는 $O(N \lg N)$이다.


코드 보기


K. Untangling Chain


원점에서 시작하여 임의의 거리를 이동하고 90도 회전을 반복한다. 회전 방향들이 주어졌을 때, 이동 거리를 잘 정해 경로를 선으로 그렸을 때 교차하지 않도록하는 문제다.

여러 가지 방법이 가능한데, 알고 있는 방법 중 가장 간단한 방법을 코드로 첨부한다. 모든 입력 데이터에 대해 답은 존재하며, 방법은 귀납법으로 증명 가능하다. 증명 방향은 이동이 진행되면 될수록 앞으로 움직이는 정사각형 영역의 이 한 단계씩 줄어들고 그 영역을 벗어나지 않는다. 시간복잡도는 $O(N)$이다.


코드 보기


B. Connect3


두 사람이 4x4 크기의 격자판에서 번갈아가면서 3목을 진행한다. 단, 돌을 놓을 때는 맨 밑바닥에 놓거나, 놓으려는 자리 밑에 돌이 있어야지만 놓을 수 있다. 이 때 후공이 특정 위치에 돌을 놓는 순간 이기게 되는 경우의 수를 구하는 문제다.

기본적으로 돌을 놓기 위해서는 맨 밑바닥에 놓거나 놓으려는 자리 밑에 돌이 있어야한다. 때문에 가능한 경우의 수를 간략하게 계산하면, 최대 $(2^5-1)^4 = 923,521$가지 밖에 되지 않는다. 그리고 4x4 게임판 상태 표현은 $0$이상 $3^{16} = 43,046,721$미만의 정수 하나로 할 수 있다. 이러한 수를 살펴보면 이 문제는 간단히 brute force하여 해결할 수 있는 문제라는 것을 알 수 있다.


코드 보기


G. Rectilinear Regions


오른쪽으로 내려가거나, 오른쪽으로 올라가는 '계단' 모양의 선 L과 U가 주어진다. 두 선에 의해 생기는 닫힌 직사각형 영역 중 선 L의 부분이 밑에 있고, 선 U의 부분이 위에 있는 직사각형 영역의 갯수와 면적 합을 구하는 문제다. 주어지는 꼭지점들의 X좌표는 서로 다르고, Y좌표 또한 서로 다르다.

각 선의 꼭지점 부분이 X좌표 순서대로 주어진다. 이를 이용해 plane sweeping을 진행하면 어렵지 않게 해결할 수 있다. 코드의 모양은 Merge Sort의 merge 과정과 유사하다. 시간복잡도는 $O(N)$이다.


코드 보기


I. Slot Machines


길이가 N인 수열이 주어진다. 이 수열의 왼쪽 $k$개의 원소를 제외하면 왼쪽에서부터 주기 $p$를 갖는다. 이 때, $k+p$가 최소가 되는 $k$, $p$를 구하는 문제다. 만약 $k+p$가 최소인 경우가 여러가지라면, $p$가 최소가 되는 경우를 찾으면 된다. 단, $p > 0$이다.

편의상 설명에서는 수열 대신 문자열을 사용하겠다. 수열의 수가 하나의 문자가 된 것일 뿐 달라지는 것은 전혀 없다.

우선, 입력으로 들어온 수열을 좌우반전시키고 KMP 알고리즘을 이용해서 실패함수 $f$의 값을 구하자.


입력으로 문자열 "EDBACBACBA"가 주어졌고, 이를 좌우반전시킨 문자열 "ABCABCABDE"가 있다고 하자. $8$번째 문자의 실패함수 $f(8)=5$라는 것은 4번째 문자와 1번째 문자가 같고, 5번째 문자와 2번째 문자가 같고, ..., 8번째 문자와 5번째 문자가 같다는 것을 의미한다. 이는 입력으로 들어온 문자열의 $k$, $p$ 값 후보로 $k=2$, $p=3$이 가능하다는 것이고, 또한 $k=2$일 때 가장 작은 $p$가 됨도 알 수 있다. 이 경우 $k+p = 10 - f(8) = 5$라는 것이고 문제에서 $k+p$ 값을 최소화하라고 하였으니, $N - f(i)$ 중 제일 작은 값을 찾으면 된다. 시간복잡도는 $O(N)$이다.


코드 보기


L. Vacation Plans


최대 3명의 사람이 서로 다른 방향성 그래프에 살고 있다. 각 사람은 첫 날 자신이 속한 연결그래프의 1번 도시에 살고 있다. 각 사람은 날이 지날 때마다, 자신이 있는 정점의 호텔에 머물 것인지, 아니면 인접한 다른 정점으로 이동할 것인지 정할 수 있다. 호텔에 머무는데 특정 비용이 들고, 간선을 통해 이동할 때 특정 비용이 있다. 각 그래프에는 한 개의 공항이 있는데 세 사람이 모두 같은날 공항에 도착하기 위한 비용합의 최소값을 구하는 문제다.

편의상 항상 3명의 사람이 있다고 하자. 만약 입력으로 들어온 사람의 수가 2명인 경우에는, 가상의 3번째 사람과 그래프를 만들어, 3번째 그래프의 정점 개수는 1개이며, 공항은 1번 정점에 있고, 1번 정점의 호텔 비용이 0이라고 생각하면 된다. 또한 호텔에 머무는 것을 self edge로 표현할 수 있다. 그러면 호텔에 머무는 선택지를 self edge를 통해 간선 이동을 하는 것으로 볼 수 있어서 좀 더 문제가 단순해진다.

사람들에게 번호를 0번부터 매기자. 그리고 $i$번 사람이 있는 그래프의 정점 개수를 $N_i$, 간선 개수를 $M_i$라고 하자.


[Dijkstra 풀이]

사람들이 각 날 동시에 움직이는 것이 아니라, 0번 사람부터 2번 사람까지 차례대로 움직인다고 생각하자. 이제 아래와 같은 DP 배열을 생각해보자.

D[i][j][k][l] = 어떤 날, 0번 사람은 i번 정점에, 1번 사람은 j번 정점에, 2번 사람은 k번 정점에 있고, 이제 l번 사람이 이동할 차례일 때 여태까지 지불한 비용합의 최소값

DP 배열의 상태 개수 $V = N_0 \times N_1 \times N_2 \times 3$이다. 현재 상태에서 다음 상태로 이동 가능한 경우 방향성 간선으로 표시했을 때 간선의 수 $E = (N_0N_1N_2(M_0+M_1+M_2))$이다. 이제 DP 배열의 내용을 Dijkstra 알고리즘을 이용하여 계산하면 시간복잡도 $O((E+V) \lg V)$에 해결할 수 있다. 실행시간은 1초 시간제한에 약 0.8초 정도 나온다.


코드 보기


[Bellman Ford 풀이]

정답이되는 날까지 걸리는 최대 기간은 $X = N_0 \times N_1 \times N_2$보다 작다. 이를 이용하여, 아래와 같은 DP 배열을 생각해보자.

D[x][i][j] = x일째 i번 사람이 j번 정점에 있을 때 최소 비용

0이상 $X$미만인 모든 x에 대해 D[x][0][T[0]]+D[x][1][T[1]]+D[x][2][T[2]]의 최소값을 구하면 답이 된다. 이 때, T[i]는 i번 사람이 있는 그래프에서 공항의 위치다. 실제로 코딩할 때, 3차원 배열이 아닌 toggling 기법을 이용하여 2차원 배열로 구현할 수 있다. 시간복잡도는 $O(N_0N_1N_2(M_0+M_1+M_2))$이며, 실행시간은 1초 시간제한에 약 0.2초 정도 나온다.


코드 보기


E. How Many to Be Happy


N개의 정점과 M개의 간선으로 이루어진 그래프가 주어진다. 각 간선에 대해 자신을 포함한 MST가 존재하기 위해 제거해야되는 간선의 최소 개수의 합을 구하는 문제다.

a번 정점과 b번 정점을 연결하는 가중치 c인 간선이 있다고 하자. 이 간선을 포함한 MST가 존재하기 위한 필요충분조건은 a번 정점과 b번 정점을 연결하는 경로 중 가중치가 c보다 작은 간선으로만 이루어진 경로가 없는 것이다. 이 때, 제거해야하는 간선의 최소 개수는 가중치가 c보다 작은 간선들만 있는 새로운 그래프를 만들고, 그 그래프에서 a번 정점과 b번 정점 사이의 minimum cut이 된다.

Minimum cut은 maximum flow로 구할 수 있으며, maximum flow를 구하는 여러 알고리즘이 존재한다. 대부분의 maximum flow 알고리즘은 시간복잡도 상으로는 시간초과가 나올 것 같아보이지만, 이 문제에서는 간단한 Ford-Fulkerson 방법으로도 빠른 시간안에 통과한다. 첨부한 코드는 내가 알고 있는 실험적으로 제일 빠른 maximum flow 코드다.


코드 보기


A. Broadcast Stations


N개의 정점으로 이루어진 트리가 주어진다. 정점에는 기지국을 놓을 수 있는데, 세기가 s인 기지국을 놓게 되면 자기 자신을 포함하여 거리 s이내의 정점에 신호가 간다. 적당히 기지국을 배치하여, 모든 정점이 신호를 수신하면서 세기 s의 합이 최소가 되도록 하는 문제다.


[제곱시간 풀이]

우선 트리를 1번 정점이 루트인 루트가 있는 트리로 만들자. 그리고 다음과 같은 두 개의 DP 배열을 생각하자.

D[i][j] = i가 루트인 서브트리에서 i번 정점에서 남는 신호 세기가 j인 경우 세기 합의 최소값

E[i][j] = i가 루트인 서브트리에서 i번 정점에서부터 j 단계 동안 신호를 수신하지 못한 정점이 있는 경우 세기 합의 최소값

이 때 DP 값을 계산하는 것은 비교적 어렵지 않게 가능하다. 이 문제에서 허들인 것은 언뜻보면 시간복잡도가 $O(N^3)$이 되어서 시간초과가 날 것 같다는 부분이다. 시간복잡도를 정확히 계산해보면, 각 정점 i에 대해 필요한 시간복잡도는 $O(\deg(i) \times N)$이 되고, 모든 i에 대해 이를 더하면 총 시간복잡도는 $O(N^2)$이 된다.


코드 보기


[선형시간 풀이]

선형시간 풀이에 접근하기 위해서는 다음과 같은 lemma가 필요하다.

lemma) 트리에서 임의의 지름을 구하고, 그 지름 위에 있는 정점들에만 기지국을 놓아도 최적해를 구할 수 있다.

풀이 준비 중.


코드 보기


J. Strongly Matchable


풀이 준비 중.


코드 보기


댓글
댓글쓰기 폼