본문 바로가기

About/Algorithm

[Programmers] 양과 늑대 (Python 풀이) - 2022 KAKAO BLIND RECRUITMENT

https://programmers.co.kr/learn/courses/30/lessons/92343

 

코딩테스트 연습 - 양과 늑대

[0,0,1,1,1,0,1,0,1,0,1,1] [[0,1],[1,2],[1,4],[0,8],[8,7],[9,10],[9,11],[4,3],[6,5],[4,6],[8,9]] 5 [0,1,0,1,1,0,1,0,0,1,0] [[0,1],[0,2],[1,3],[1,4],[2,5],[2,6],[3,7],[4,8],[6,9],[9,10]] 5

programmers.co.kr


풀이

이 문제는 이진 트리에서 조건에 따라 순회 가능한 모든 경우의 수를 탐색하면서 최대 양의 개수를 구하면 정답이 됩니다. 순회는 순서에 따라 영향을 받습니다. 따라서 같은 번호를 순회하더라도 여러 경우의 수가 생길 수 있습니다.

입력 및 초기화

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from collections import defaultdict, deque  #
from copy import deepcopy
 
is_wolf = list()
num2edges = defaultdict(list)
max_sheep = 0
 
def solution(info, edges):
    global is_wolf, num2edges, max_sheep
    is_wolf = info # 전역변수에 할당
    used = [False* len(is_wolf) # 방문한 노드 확인 용 변수
 
    for e_from, e_to in edges:
        num2edges[e_from].append(e_to) # 연결된 엣지 리스트에 추가
 
    # start
    find_max_recursive(0, used, 00, [])
    return max_sheep
cs
 
10번 줄에서 infois_wolf에 할당합니다. 함수에서 참고하기 위해 전역변수로 설정하였습니다.
13~14번 줄에서 num2edges는 인덱스로 정해진 번호에 연결된 노드들을 리스트로 가지는 변수입니다. 

위와 같이 노드가 구성되어 있을 때 numn2edges 값을 다음과 같습니다. 출력해보면 다음과 같은 값을 가집니다.

1
2
3
4
5
6
7
8
9
# num2edges
{
    0: [18], 
    1: [24], 
    8: [79], 
    9: [1011], 
    4: [36],
    6: [5]
}
cs

입력 및 초기화가 완료되면 find_max_recursive() 함수에서 최대 양의 수를 찾습니다.

최대 양의 수 찾기

find_max_recursive() 함수는 다음과 같이 재귀함수로 이루어져 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
def find_max_recursive(current_loc, used, nsheep, nwolf, can_go):
    global max_sheep
 
    if used[current_loc]: return  # 현재 노드를 방문한 경우 return
    used[current_loc] = True  # 방문 기록
 
    if is_wolf[current_loc]:  # 늑대인 경우 늑대 count += 1
        nwolf += 1
    else:
        nsheep += 1  # 양인 경우 양 count += 1
        max_sheep = max(max_sheep, nsheep)  # 양 최대 수 갱신
 
    if nsheep <= nwolf: return  # 늑대 수가 양의 수와 같거나 많은 경우 return
 
    can_go.extend(num2edges[current_loc])  # 현재 노드와 연결된 노드를 추가함
    for next_loc in can_go:
        # q에 저장된 노드서 하나를 가져와서 재귀함수 요청
        # 이 때 다음 q에는 현재 노드를 제외한 리스트로 재구성하여 재귀함수 요청
        find_max_recursive(next_loc, deepcopy(used), nsheep, nwolf,
                           can_go=[loc for loc in can_go if loc != next_loc and not used[loc]])
cs

 

7~11번 줄에서 현재 노드가 양인지 늑대인지에 따라 양의 수 혹은 늑대의 수를 갱신합니다. 양의 수가 더해진 경우 양 최대 수를 갱신합니다.

13번 줄에서 늑대 수가 양의 수보다 많아진 경우 종료합니다.

15번 줄에서 현재 노드와 연결된 노드들을 can_go 리스트에 추가합니다.

16~19번 줄에서 can_go 리스트에 저장된 노드들을 하나씩 가져와서 재귀함수를 요청합니다. 다음 재귀함수에서 current_loc 가 next_loc가 됩니다. 그리고 can_go 리스트에 저장된 노드들 중 next_loc는 사용한 변수가 되기 때문에 next_loc를 제외한 노드들로 can_go를 재구성하여 재귀함수를 요청합니다.

전체 소스 코드

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
from collections import defaultdict, deque  #
from copy import deepcopy
 
is_wolf = list()
num2edges = defaultdict(list)
max_sheep = 0
 
 
def find_max_recursive(current_loc, used, nsheep, nwolf, can_go):
    global max_sheep
 
    if used[current_loc]: return  # 현재 노드를 방문한 경우 return
    used[current_loc] = True  # 방문 기록
 
    if is_wolf[current_loc]:  # 늑대인 경우 늑대 count += 1
        nwolf += 1
    else:
        nsheep += 1  # 양인 경우 양 count += 1
        max_sheep = max(max_sheep, nsheep)  # 양 최대 수 갱신
 
    if nsheep <= nwolf: return  # 늑대 수가 양의 수와 같거나 많은 경우 return
 
    can_go.extend(num2edges[current_loc])  # 현재 노드와 연결된 노드를 추가함
    for next_loc in can_go:
        # q에 저장된 노드서 하나를 가져와서 재귀함수 요청
        # 이 때 다음 q에는 현재 노드를 제외한 리스트로 재구성하여 재귀함수 요청
        find_max_recursive(next_loc, deepcopy(used), nsheep, nwolf,
                           can_go=[loc for loc in can_go if loc != next_loc and not used[loc]])
 
 
def solution(info, edges):
    global is_wolf, num2edges, max_sheep
    is_wolf = info # 전역변수에 할당
    used = [False* len(is_wolf) # 방문한 노드 확인 용 변수
 
    for e_from, e_to in edges:
        num2edges[e_from].append(e_to) # 연결된 엣지 리스트에 추가
    print(num2edges)
    for i, v in num2edges.items():
        print(i, ":", v)
    # start
    find_max_recursive(0, used, 00, [])
    return max_sheep
cs