Home 행성터널 백준 2887번 그래프
Post
Cancel

행성터널 백준 2887번 그래프

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

때는 2040년, 이민혁은 우주에 자신만의 왕국을 만들었다. 왕국은 N개의 행성으로 이루어져 있다. 민혁이는 이 행성을 효율적으로 지배하기 위해서 행성을 연결하는 터널을 만들려고 한다.

행성은 3차원 좌표위의 한 점으로 생각하면 된다. 두 행성 A(xA, yA, zA)와 B(xB, yB, zB)를 터널로 연결할 때 드는 비용은 min(xA-xB,yA-yB,zA-zB)이다.

민혁이는 터널을 총 N-1개 건설해서 모든 행성이 서로 연결되게 하려고 한다. 이때, 모든 행성을 터널로 연결하는데 필요한 최소 비용을 구하는 프로그램을 작성하시오.

음 일단 제 생각에는 행성이 5개가 있고 각 모든 도시의 거리를 구하고 최소 비용으로 정렬을 하고 차례대로 합쳐나가면 될듯합니다.

다시 정리를 하면 모든 노드에서 각 노드로 가는 비용을 계산을 합니다. 그리고 비용이 낮은 순으로 정렬을해서 사이클이 일어나지 않는다면 합쳐나가는 방식을 사용했습니다.

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
n = int(input())
map_list = []
for _ in range(n):
    map_list.append(list(map(int,input().split())))
    
parent = [0]*(n+1)
for i in range(1,n+1):
    parent[i] = i
    
def find_length(a,b):
    length = min(abs(a[0]-b[0]),abs(a[1]-b[1]),abs(a[2]-b[2]))
    return length

#특정 원소가 속한 집합을 찾기
def find_parent(parent, x):
    #로트 노드가 아니라면, 로트 노드를 찾을 때까지 재귀적으로 호출
    if parent[x] != x:
        parent[x] = find_parent(parent, parent[x])
    return parent[x]

#두 원소가 속한 집합을 찾기
def union_parent(parent,a,b):
    a = find_parent(parent,a)
    b = find_parent(parent,b)
    if a < b:
        parent[b] = a
    else:
        parent[a] = b

이전 그래프 문제와 비슷합니다. 값을 입력받고 추가적으로 조건에 따라 x,y,z를 비교해서 거리를 반환하는 함수를 하나더 만들었습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
edges = []
for i in range(n):
    for j in range(i+1,n):
        temp_list = find_length(map_list[i],map_list[j])
        edges.append((temp_list,i,j))

edges.sort()

result = 0
#간선을 하나씩 확인하며
for edge in edges:
    cost, a, b = edge
    #사이클이 발생하지 않는 경우에만 집합에 포함
    if find_parent(parent, a) != find_parent(parent, b):
        union_parent(parent, a, b)
        result += cost

이렇게 했는데!

memory error

메모리 초과가 나왔습니다. 아무래도 각 노드에 대해서 모든 거리를 계산하는 것은 비효율적이었나 봅니다.

터널의 비용을 계산하기 위해서는 각 x,y,z축의 하나만 고려를 해도 되니 이를 기준으로 정렬을 수행하는 식으로 접근을 합니다.

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#특정 원소가 속한 집합을 찾기
def find_parent(parnet, x):
    #루트 노드가 아니라면, 루트 노드를 찾을 때까지 재귀적으로 호출
    if parent[x] != x:
        parent[x] = find_parent(parent, parent[x])
    return parent[x]

#두 원소가 속한 집합을 합치기
def union_parent(parent, a,b):
    a = find_parent(parent, a)
    b = find_parent(parent, b)
    if a<b:
        parent[b] = a
    else:
        parent[a] = b
        
n = int(input())
parent = [0]*(n+1)
for i in range(1,n+1):
    parent[i] = i
edges = []
result = 0

x = []
y = []
z = []

#모든 노드에 대한 좌표 값 입력받기
for i in range(1,n+1):
    data = list(map(int, input().split()))
    x.append((data[0],i))
    y.append((data[1],i))
    z.append((data[2],i))

x.sort()
y.sort()
z.sort()

#인접한 노드들로부터 간선 정보를 추출하여 처리
for i in range(n-1):
    #비용순으로 정렬하기 위해서 튜플의 첫 번째 원소를 비용으로 설정
    edges.append((x[i+1][0]-x[i][0], x[i][1], x[i+1][1]))
    edges.append((y[i+1][0]-y[i][0], y[i][1], y[i+1][1]))
    edges.append((z[i+1][0]-z[i][0], z[i][1], z[i+1][1]))
    
#간선을 비용순으로 정렬
edges.sort()

#간선을 하나씩 확인하며
for edge in edges:
    cost, a, b = edge
    #사이클이 발생하지 않는 경우에만 집합에 포함
    if find_parent(parent,a) != find_parent(parent, b):
        union_parent(parent, a, b)
        result += cost
        
print(result)

각 x,y,z를 기준으로 정렬을하고 그리고 이를 기준으로 간선정보를 추출을 하게 되는데 그러면 자연스럽게 가장 비용이 낮은것끼리 엮이게 됩니다. 그리고 이를 서로소집합 확인으로 사이클을 확인하여 비용을 계산합니다.

This post is licensed under CC BY 4.0 by the author.

Comments powered by Disqus.