고등학생때 배웠던 순열, 조합과 똑같은 내용입니다. 하지만 수학이랑 다르게 직접 경우의 수를 계산하면서 확인하는 구현 문제를 풀을 예정입니다.
C++ 사용자는 next_permutaion을 이용하여 조합도 구할 수 있다고 합니다.
순열과 조합
사용법
우리는 6주차 자주 사용하는 모듈에서 잠깐 itertools 모듈에 있는 순열과 조합 방법을 읽었을 것입니다.
from itertools import permutations as pm # 순열from itertools import combinations as cb # 조합
사용법은 pm, cb 둘 다 (순열/조합을 뽑아낼 자료형), (뽑아낼 길이)를 입력하면 됩니다.
# 순열from itertools import permutations as pma = [1,2,3,4]for t inpm(a, 2):print(t)# (1, 2)# (1, 3)# (1, 4)# (2, 1)# (2, 3)# (2, 4)# (3, 1)# (3, 2)# (3, 4)# (4, 1)# (4, 2)# (4, 3)# 혹은 길이가 2이므로 변수를 2개로 해서 각각 출력할 수 있음for x, y inpm(a,2):print(x, y)# 출력은 위에 괄호만 제거하면 같음
#조합from itertools import combinations as cba = [4,3,2,1]for t incb(a, 2):print(t)# (4, 3)# (4, 2)# (4, 1)# (3, 2)# (3, 1)# (2, 1)# 조합도 마찬가지로 길이가 2이므로 for문에 변수를 2개 넣어 각각 출력 가능 for x, y incb(a, 2):print(x, y)
우리는 이미 고등학생때 순열이 무엇인지, 조합이 무엇인지 배웠기 때문에 따로 설명할 필요가 없을 것 같습니다.
바로 문제를 풀어보겠습니다.
연습 문제
연습 문제는 N과 M 시리즈 문제를 2문제 풀겠습니다. 참고로 모든 N과 M 문제들은 다음에 배울 재귀 함수로 전부 풀 수 있습니다.
BOJ 10974
순열을 사전 순으로 출력하라고 합니다.
일단 단순히 순열만 사용하면 정렬이 되지 않기 때문에 우리는 정렬된 값을 permuations에 넣고, for문과 join을 이용해 출력하면 될 것 같습니다.
아니면 따로 permutations를 구한 값을 리스트에 저장한 다음 정렬하고 출력해도 됩니다.
# 방법 1from itertools import permutations as pmn =int(input())arr = [i for i inrange(1, n+1)]for t inpm(arr, n):print(' '.join(map(str,t)))# 튜플안의 값이 int이므로 str로 바꿈# 방법 2from itertools import permutations as pmn =int(input())arr = [i for i inrange(n, 0, -1)] # 배열을 아무렇게나 넣음ans =list(pm(arr, n))ans.sort()for i inrange(len(ans)):print(' '.join(map(str,ans[i])))
BOJ 2798
N개의 카드중에서 3장을 골라 합이 M을 넘지 않으면서도 가장 큰 값을 구하라고 합니다. 넘지 않은 것이라면 3장의 합이 M이여도 된다는 뜻이네요.
이 문제는 순열, 조합 모두 풀 수 있습니다. 순열은 카드를 뽑는 순서까지 고려해서 경우의 수를 모두 뽑아내는 것이고, 조합은 카드를 뽑는 순서는 고려하지 않아서 순열보다 더 적은 경우의 수를 뽑아낼 수 있습니다.
그래서 우리는 조합을 이용하여 풀어보겠습니다. 일단 입력값을 받는 코드를 만들어줍시다.
from itertools import combinations as cbn, m =map(int,input().split())arr =list(map(int,input().split()))
여기서 답을 출력할 변수 ans을 만들어주고, for문과 cb()를 이용하여 ans의 값을 업데이트하면 됩니다.
from itertools import combinations as cbn, m =map(int,input().split())arr =list(map(int,input().split()))ans =0for t incb(arr, 3):ifsum(t)<= m: ans =max(ans, sum(t))print(ans)
2022 KAKAO BLINE RECRUITMENT에서 4번 문제로 중복 조합 문제가 출제되었습니다. 백트래킹으로도 풀 수 있었지만, 중복 조합인 것을 파악할 수 있으면 이 방법이 구현이 더 쉽습니다.
단순 조합을 사용할 때는 from itertools import combination이라면 중복 조합은 아래 코드를 사용하면 됩니다.
# 중복 조합from itertools import combination_with_replacement as cbwrfor arr incbwr([1, 2, 3, 4], 2):#cbwr(선택할 배열, 뽑는 갯수)print(arr)# 중복을 포함하여 [1, 2, 3, 4]에서 원소 2개를 포함하여 출력
문제를 풀어봅시다.
1부터 N에서 숫자를 M개 뽑는데, 같은 수를 여러 번 뽑아도 된다고 합니다. 같은 수를 여러 번 뽑을 수 있으면 중복 조합을 통해 문제를 풀 수 있습니다.
일단 n과 m을 입력 받아 봅시다.
n, m =map(int, input().split())
그리고 1부터 n까지의 배열을 만들어야 하니 배열을 만들어봅시다.
n, m =map(int, input().split())arr = [i for i inrange(1, n+1)]
이제 중복 조합 함수를 불러와서 출력을 해주면 됩니다.
from itertools import combinations_with_replacement as cbwrn, m =map(int, input().split())arr = [i for i inrange(1, n+1)]for x incbwr(arr, m):print(' '.join(map(str, x)))