알고리즘/BOJ

[BOJ/python]10775번 공항

frog-in-well 2022. 7. 4. 22:26

백준 10775번 공항 파이썬

문제 링크

 

10775번: 공항

예제 1 : [2][?][?][1] 형태로 도킹시킬 수 있다. 3번째 비행기는 도킹시킬 수 없다. 예제 2 : [1][2][3][?] 형태로 도킹 시킬 수 있고, 4번째 비행기는 절대 도킹 시킬 수 없어서 이후 추가적인 도킹은 불

www.acmicpc.net

한 번에 푼 문제는 아니지만 단계적으로 잘 풀어서 기분이 좋았다. 유니온 파인드를 이용해서 풀어야 하는 문제다.

처음에는 그리디하게 가능한 가장 번호가 큰 공항에 비행기를 배치했다. 새로운 비행기에 할당된 공항이 중복되면 기존에 있던 비행기는 왼쪽으로 한 칸씩 밀어서 배치가 가능하다. 이를 이중 반복문을 통해 구현했다.

1. 코드 (greedy, 시간 초과)

# 공항
G, P = int(input()) , int(input())
airport = [-1 for _ in range(G+1)]
ans=0
for i in range(P):
    g= int(input())
    
    if airport[g] == -1:
        airport[g]=1
        ans+=1
        
    else:
        check = ans
        for j in range(g,0,-1):
            if airport[j] == -1:
                airport[j]=1
                ans+=1
                break
        if ans==check:
            print(ans)
            break

당연히 시간초과가 발생했다.

2-1. union - find풀이

빈 공항 중 가장 오른쪽에 있는 칸을 찾는 방법은 유지한채 시간을 줄일 수 있는 방법을 생각했다. 반복문을 사용하지 않고 union-find를 통해 중복된 공항을 선택하면 O(1)시간으로 비어있는 공항을 알려주는 알고리즘을 떠올렸다.

현재 공항보다 작은 숫자의 공항 중에서 가장 오른쪽에 비어있는 칸을 루트로 union한다. 이렇게 되면 여전히 greedy하게 공항을 배치할 수 있으며 중복된 공항을 선택하면 가능한 공항 중 가장 큰 번호를 find를 통해 알려준다.

ex)1번에서 7번까지 공항이 있고, 3번 6번 7번에 이미 greedy하게 배치된 경우를 가정하자.

2(root)-3 / 5(root)-6-7 과 같이 트리가 만들어진다.(find를 통해 7번의 부모 노드는 5번이 된다.)

이 때 다음 비행기가 7번 게이트를 가려고 하면 5번 게이트를 O(1)에 찾을 수 있게 된다.

어떠한 공항에도 도킹할 수 없는 경우는 find를 했지만 0번 노드를 반환한 경우이다.

2-2. 코드 (union-find + greedy)

# 공항
def find(u):
    if p[u]<0:
        return u
    
    p[u]=find(p[u])
    return p[u]

def union(u,v): # u가 루트
    u,v = find(u),find(v)

    if u==v :
        return

    p[v]=u
    
G, P = int(input()) , int(input())
p=[-1 for i in range(G+1)]
ans=0
for i in range(P):
    g= int(input())
    target = find(g)
    if target==0:
        break
    union(target-1, target)
    ans+=1
    
print(ans)