본문 바로가기

알고리즘

[파이썬 | BOJ | 2565] 전깃줄

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

 

2565번: 전깃줄

첫째 줄에는 두 전봇대 사이의 전깃줄의 개수가 주어진다. 전깃줄의 개수는 100 이하의 자연수이다. 둘째 줄부터 한 줄에 하나씩 전깃줄이 A전봇대와 연결되는 위치의 번호와 B전봇대와 연결되는 위치의 번호가 차례로 주어진다. 위치의 번호는 500 이하의 자연수이고, 같은 위치에 두 개 이상의 전깃줄이 연결될 수 없다.

www.acmicpc.net

문제

두 전봇대 A와 B 사이에 하나 둘씩 전깃줄을 추가하다 보니 전깃줄이 서로 교차하는 경우가 발생하였다. 합선의 위험이 있어 이들 중 몇 개의 전깃줄을 없애 전깃줄이 교차하지 않도록 만들려고 한다.

예를 들어, <그림 1>과 같이 전깃줄이 연결되어 있는 경우 A의 1번 위치와 B의 8번 위치를 잇는 전깃줄, A의 3번 위치와 B의 9번 위치를 잇는 전깃줄, A의 4번 위치와 B의 1번 위치를 잇는 전깃줄을 없애면 남아있는 모든 전깃줄이 서로 교차하지 않게 된다.

전깃줄이 전봇대에 연결되는 위치는 전봇대 위에서부터 차례대로 번호가 매겨진다. 전깃줄의 개수와 전깃줄들이 두 전봇대에 연결되는 위치의 번호가 주어질 때, 남아있는 모든 전깃줄이 서로 교차하지 않게 하기 위해 없애야 하는 전깃줄의 최소 개수를 구하는 프로그램을 작성하시오.

입력

첫째 줄에는 두 전봇대 사이의 전깃줄의 개수가 주어진다. 전깃줄의 개수는 100 이하의 자연수이다. 둘째 줄부터 한 줄에 하나씩 전깃줄이 A전봇대와 연결되는 위치의 번호와 B전봇대와 연결되는 위치의 번호가 차례로 주어진다. 위치의 번호는 500 이하의 자연수이고, 같은 위치에 두 개 이상의 전깃줄이 연결될 수 없다.

출력

첫째 줄에 남아있는 모든 전깃줄이 서로 교차하지 않게 하기 위해 없애야 하는 전깃줄의 최소 개수를 출력한다.

풀이

문제에서 주어진 조건을 지키면서 최대한 많은 전깃줄을 보존하는 방법은, 모든 전기줄의 A, B 번호가 같은 경우이다.

즉 (1,1), (2,2) ... (N, N)일 때 전기줄을 최대한 이용할 수 있다.

전기줄이 교차하는 조건은, (A[i], B[i]), (A[i+1], B[i+1])이 있을때 A[i] < A[i+1]인데 B[i] > B[i+1]인 경우이다. (같은 경우는 주어지지 않는다.)

 

따라서 A를 기준으로 정렬한 후, 정렬된 숫자 B들의 list에 대해서 LIS (longest increasing subsequence) 알고리즘을 수행한다.

 

LIS 알고리즘은 O(n^2) 방법과 O(nlgn) 방법이 있는데, O(nlgn)방법은 잘 이해하지 못해서 O(n^2)를 수행했다.

LIS 알고리즘의 쉬운 방법의 기본아이디어는 다이내믹 프로그래밍이다.

 

i 0 1 2 3 4 5 6
arr 10 20 30 10 40 60 20
d 1 2 3 1 4 5 2

d[i]는 arr[i]를 마지막으로 하는 가장 LIS 값이다. 즉 j∈[0, i)까지 범위를 가지는 arr값 중에서 arr[j] < arr[i] 이면서 가장 최대인 d[j]값에다가 +1을 하면 d[i]값이 된다.

 

코드로 구현하면 다음과 같다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# [파이썬 | BOJ | 2565] 전깃줄
import sys
read = sys.stdin.readline
 
def lis(arr):
    dp = [0 for _ in range(len(arr))]
    dp[0= 1
    for i in range(1, N):
        maxval = 0
        for j in reversed(range(i)):
            if arr[j] < arr[i] and maxval < dp[j]:
                maxval = dp[j]
        dp[i] = maxval + 1
    #print(dp)
    return max(dp)
 
= int(read())
 
dp = [0 for _ in range(N)]
AB = []
for _ in range(N):
    AB.append(list(map(int,read().split())))
AB.sort()
= []
for b in AB:
    B.append(b[1])
ans = lis(B)
print(N-ans)
cs