Algorithm study/재귀

재귀함수를 이용해 순열 구하기

카누가 좋아요 2023. 7. 16. 00:08

✏️ 목표

1부터 n까지 번호가 적힌 구슬이 있는데, 이 중 m개를 뽑아 일렬로 나열하는 방법을 모두 출력해 보자.

(이때 출력 순서는 사전순으로 오름차순으로 한다.)

 

📍 입력

첫 번째 줄에 자연수 n(3 <= n <= 10)과 m(2 <= m <= n)이 주어진다.

 

 

 

❓ 순열

n개의 수 중에서 r개를 뽑아 순서대로 배열하는 경우의 수를 나타낸다.

중복순열에서는 동일한 수를 여러 번 뽑는 것이 가능하지만 그냥 순열에서는 하나의 수는 한 번만 뽑을 수 있다는 점에서 차이를 보인다.

수를 뽑았을 때 같은 구성이더라도 배열한 순서가 다르면 서로 다른 순열로 취급하는 것은 같다.

 

<ex>

1부터 3까지의 수 중에서 2개를 뽑아 순서대로 배열하면 (순열을 구하면)

(1, 2), (1, 3), (2, 1), (2, 3), (3, 1), (3, 2) 이렇게 6가지의 순열을 만드는 것이 가능하다.

 

 

 

💡 해결하기

➡️ 트리로 표현할 때 한 노드에서 n개의 간선이 뻗어나가고, 반복문(for문)을 사용하여 1부터 n까지의 숫자를 모두 돌게 하여 pick 리스트에 뽑힌 숫자(현재 i의 값)를 차례로 기록(이것이 곧 일렬로 나열하는 것)하여 트리의 레벨을 나타내는 L이 뽑아야 할 숫자의 수인 m과 같아지면 pick에 기록된 숫자를 차례로 출력하는 기본적인 과정은 중복 순열에서와 비슷하다.

 

재귀함수를 이용해 중복순열 구하기 (tistory.com)

 

재귀함수를 이용해 중복순열 구하기

✏️ 목표 1부터 N까지 번호가 적힌 구슬이 있는데, 이 중 중복을 허락하여 M번을 뽑아 일렬로 나열하는 방법을 모두 출력한 후 마지막에는 방법의 수를 출력해 보자. (이때 출력 순서는 사전순으

developingdiaryoflily.tistory.com

 

➡️ 그런데 중복순열에서와 다르게 그냥 순열에서는 숫자를 중복하여 뽑을 수 없다고 하였다. 즉, 뻗어나가는 간선 중 cut해야 할 것이 존재한다.

이를 구현하기 위해 어떤 숫자가 뽑혔는지를 기록하기 위한 체크 리스트인 ch를 만들어 주었다.

값이 1이면 그 index에 해당하는 숫자가 뽑혔다는 의미이고, 0이면 뽑히지 않았다는 의미이다.

ch의 길이는 숫자의 종류인 n보다 1 크게 만들어 주었고, 숫자 i를 선택할 때, i번째에 해당하는 부분을 1로 변경해 준다. 

그런 후 permutation 함수를 재귀 호출한다.

그 후에는 숫자 i를 선택한 것을 back 해야 하므로 ch[i]를 다시 0으로 만들어 숫자 i를 뽑지 않은 것으로 만들어 준다.

위 과정을 진행하기 전에는 ch[i]가 0인지(i가 이미 뽑힌 숫자인지)를 확인해야 한다.

 

📍 트리로 나타내보기

 

 

 

💻 Python으로 코드 작성하기

 

def permutation(L):
    global cnt
    if L == m:
        for num in pick:
            print(num, end=' ')
        print()
        cnt += 1
    else:
        for i in range(1, n + 1):
            # ch 리스트의 i번째 값이 0일 경우는 i가 뽑히지 않은 숫자임을 의미한다.
            if ch[i] == 0:
                # 숫자를 하나 고른 후 (그 숫자는 i이다.)
                pick[L] = i
                # ch 리스트의 해당 숫자에 해당하는 번째에 1 표시
                ch[i] = 1
                # permutation 함수 재귀 호출
                permutation(L + 1)
                # 뽑은 숫자를 다시 back하여 안 뽑은 상태로 돌아가기 (다음 i를 뽑기 위해)
                ch[i] = 0

n, m = map(int, input().split())
pick = [0] * m
ch = [0] * (n + 1)     # 중복을 피하기 위해 체크 리스트를 하나 만듦. 
cnt = 0
permutation(0)
print(cnt)

 

 

 

📌 참고 강의

파이썬 알고리즘 문제풀이 입문(코딩테스트 대비) 대시보드 - 인프런 | 강의 (inflearn.com)

 

파이썬 알고리즘 문제풀이 입문(코딩테스트 대비) - 인프런 | 강의

파이썬(Python)을 이용해 코딩 테스트 문제 풀이를 합니다., 개발자 취업 & 이직을 위한 핵심 코스 📝코딩테스트 대비 파이썬 알고리즘 문제풀이!  📢 수강 전 반드시 확인해주세요! 강의에서 제

www.inflearn.com