본문 바로가기

Algorithm

백준 No.2565 - 전깃줄

출처:https://www.acmicpc.net/submit/2565

 

문제

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

 

입력

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

 

출력

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

 

 

단계별 알고리즘 학습을 하는 도중 만나게 된 전깃줄 문제..

카테고리는 동적프로그래밍(Dynamic Programming)에 속하는 문제이다.

DP에서는 점화식을 세우는게 기본소양이자 가장 중요한 부분인듯한데, 나의 머리로는 도저히 점화식을 떠올릴 수 없는 경우가 너무 많다

 

가장 먼저 생각했던 방법은 두 line을 비교하여 교차한다면 dp배열에 1씩 더해주는 방식을 떠올렸다.

2중loop를 사용하긴 하지만 n의 최대값이 100이기 때문에 시간 복잡도는 오래 걸리지 않을터

 

n = int(input())

lines = []

for _ in range(n):

    lines.append(list(map(int, input().split())))

dp = [0] * n

result = 0

for i in range(n-1):

    for j in range(i+1, n):

        x, y = lines[i]

        a, b = lines[j]

        if (x > a and y < b) or (x < a and y > b):

            dp[i] += 1



for i in dp:

    if i > 0:

        result += 1



 

하지만 여지없이 틀리고 말았다...

이후로 순회방향을 바꿔보기도 하고 다양하게 시도해보았지만 "틀렸습니다"를 굉장히 많이 마주했다.

결국 집단지성(?)을 발휘하기 위해 구글링을 시도했다.

 

역시 구글링은 나를 실망시키지 않았다.

이 문제를 게시한 분들도 대다수 발상의 전환이 중요하다는 것을 깨달았다고 한다.

구현은 생각보다 간단했다. 다만 구현할 '무언가'를 찾아내는 것이 어려울 뿐.

 

문제에서 요구한 최소한의 제거가 아닌, 최대한의 증설로 접근하는 것.

한 쪽을 기준으로 sorting을 한 뒤에 다른 한 쪽에서 최대증가수열을 구하는 것이 핵심이었다.

어찌 생각해보면 당연한 것인데 왜 떠올리지 못했을까라는 생각도 든다.

 

최종적인 답안 코드는 다음과 같다.

 

n = int(input())
lines = []
for _ in range(n):
    lines.append(list(map(int, input().split())))
dp = [1] * n

lines.sort()

for i in range(n):
    for j in range(i-1, -1, -1):
        if lines[i][1] > lines[j][1]:
            dp[i] = max(dp[i], dp[j]+1)
print(n-max(dp))

 

처음 구상했던 코드보다 훨씬 간결하고 정확한 답을 도출할 수 있었다.

 

발상의 전환, 언제나 기억하자!

'Algorithm' 카테고리의 다른 글

[Algorithm] 경주로 건설 - 2020 카카오 인턴쉽  (0) 2022.05.10
2020 KAKAO BLIND RECRUITMENT  (0) 2020.11.07
백준 No.2447 - 별찍기 - 10  (0) 2020.07.31