[알고리즘] 순열 추측하기 (DFS)
(문제) 순열 추측하기 (DFS)
가장 윗줄에 1부터 N까지의 숫자가 한 개씩 적혀 있다.
그리고 둘째 줄부터 차례대로 파스칼의 삼각형처럼 위의 두개를 더한 값이 저장되게 된다.
예를 들어 N이 4 이고 가장 윗 줄에 3 1 2 4 가 있다고 했을 때, 다음과 같은 삼각형이 그려진다.
3 1 2 4
4 3 6
7 9
16
N과 가장 밑에 있는 숫자가 주어져 있을 때 가장 윗줄에 있는 숫자를 구하는 프로그램을 작성하시오.
단, 답이 여러가지가 나오는 경우에는 사전순으로 가장 앞에 오는 것을 출력하여야 한다.
입력설명
첫째 줄에 두개의 정수 N(1≤N≤10)과 F가 주어진다.
N은 가장 윗줄에 있는 숫자의 개수를 의미하며 F는 가장 밑에 줄에 있는 수로 1,000,000 이하이다.
출력설명
첫째 줄에 삼각형에서 가장 위에 들어갈 N개의 숫자를 빈 칸을 사이에 두고 출력한다.
답이 존재하지 않는 경우는 입력으로 주어지지 않는다.
테스트케이스
입력예제 | 출력예제 |
---|---|
4 16 | 3 1 2 4 |
5 39 | 4 1 3 2 5 |
9 1610 | 1 2 3 5 9 6 8 4 7 |
9 730 | 7 6 4 2 1 3 5 8 9 |
7 288 | 1 2 4 5 6 3 7 |
10 2196 | 1 6 9 4 2 3 5 10 7 8 |
해결방법
- 입력이 된다면 1~n 까지 나열 되어있는 것이다.
- 각각을 더한다. 그러면 하나의 숫자가 된다.
- 그러면 또 그들을 더하면 하나의 숫자가 된다.
- 이 반복을 통해서 1개의 출력이 f의 값가 같아지는 것이다.
전부 다 해보는 방법 밖에 없다.
순열 구하는 방법
dfs 순열 구하는 방법
순열들
- 경우 1 : 1 2 3 4
- 경우 2 : 1 2 4 3
- 경우 3 : 1 3 2 4 …
이런 것을 반복한다.
4!의 가지수 -> 24가지를 다 해본다.
각각 더한 값이 16이 발견되면 stop 하고 그 순열을 출력한다.
하지만 이런 식으로 각각 더해서 값을 얻으려고 하는 경우 시간이 오래 걸린다.
그래서 각각으로 더할 경우, 다르게 생각을 해보면 이렇게 된다.
1 2 3 4
1+2, 2+3, 3+4
1+2+2+3, 2+3+3+4
1+2+2+2+3+3+3+4 –> 1이 1개 / 2가 3개 / 3이 3개 / 4가 1개
한번 보면 뭔가 규칙
이 보인다.
규칙은 파스칼 삼각형 이항 계수 규칙
이다.
파스칼 삼각형이란?
이런식으로 만들어 진다.
해당 n개를 기준으로 n-1에 해당하는 이항 계수가 들어있는 리스트를 생성한다.
생성 후, 만들어진 순열을 각각 곱해서 f의 값과 같아지는 것 만나면 재귀를 끝낸다.
코드
def dfs(x, _sum):
if x == n and _sum == f:
# 계수 나오도록
print(*ch)
sys.exit(1)
else:
for i in range(1, n+1):
if not i in ch:
ch.append(i)
dfs(x+1, _sum + (ch[x]*b[x]))
ch.pop()
n, f = map(int, input().split())
b = [1] * n
# 파스칼 삼각형 이항 계수 규칙 조합 이용
for i in range(1, n):
b[i] = b[i-1] * (n-i) // i
ch = []
dfs(0, 0)
댓글남기기