고등학교 확률과 통계라는 과목에서 중복조합에 대한 내용을 공부한적이 있다.
그 중 중복조합과 관련된 문제 중 가장 일반적인 문제가
a + b + c = 6 일 때 음이 아닌 정수 의 (a, b, c) 쌍이 몇개 인지 구하는 것이다.
이 문제를 중복 조합 공식으로 풀면 그 개수만 알 뿐 어떤 조합이 생기는지는 알 수 없다.
그래서 이를 코드로 작성하면 아래와 같다.
static void comb()
{
for (int a = 0; a <= 6; a++)
{
for (int b = 0; b <= 6; b++)
{
for (int c = 0; c <= 6; c++)
{
if (a + b + c == 6)
{
printf("%d %d %d\n", a, b, c);
}
}
}
}
}
단순히 반복문을 중첩해서 구하는 것이다.
여기서 a + 2b + c = 6 과 같은 식은 b에 대한 조건을 추가하여 구할 수 있다.
2b <= 6 이므로, b <= 3 여야만 한다. 따라서 아래와 같이 작성하면 된다.
static void comb()
{
for (int a = 0; a <= 6; a++)
{
for (int b = 0; b <= 6 / 2; b++)
{
for (int c = 0; c <= 6; c++)
{
if (a + 2 * b + c == 6)
{
printf("%d %d %d\n", a, b, c);
}
}
}
}
}
이렇게 하면 중복 조합의 모든 경우를 볼 수 있다. 그러나 입력에 따라 유연하게 동작하지 않기 때문에, 어떤 조합의 결과를 보고 싶을 때 마다 코드를 수정해야 한다.
그래서 재귀를 이용하여 아래와 같이 작성 할 수 있다.
static int N, K;
static int v_list[10];
static void comb(int cnt, int v)
{
if (v == K)
{
for (int i = 1; i < cnt; i++)
printf("%d ", v_list[i]);
puts("");
return;
}
if (cnt > N)
return;
for (int i = 0; i <= K; i++)
{
int val = v + i;
v_list[cnt] = i;
comb(cnt + 1, val);
}
}
int main()
{
N = 3; K = 6;
comb(1, 0);
}
N은 순서쌍을 이루는 정수의 개수, K는 원하는 값을 말한다.
재귀의 탈출 조건은 크게 누적된 값이 K가 되는 경우와, cnt > N 일 때이다.
이에 대해서 a + b + c = 6 을 예로 들어보겠다.
먼저 a는 0이 선택되고 이는 v_list[1] = 0 이다.
이제 b를 선택할 차례이고 마찬가지로 0을 선택한다. v_list[1 + 1] = v_list[2] = 0 이다.
현재 2개의 값이 선택 된 것이다.
이제 c를 선택할 차례이다. 역시 0을 선택하고 v_list[2 + 1] = v_list[3] = 0 이다.
그리고 재귀 호출 을 하게 되면 cnt 는 4가 된다. 즉 더 이상 선택 할 수 없음을 말하는 것이다.
이제 c가 6이 선택된다. v_list[3] = 6 이고 val = (0 + 0) + 6 = 6 이다.
다시 재귀 호출 되면 v == 6 == K 이므로 기록된 값 들을 cnt 만큼 만 출력하는 것이다.
이제 이 코드를 다시 응용 해서 a + 2b + c = 6 과 같은 조합 문제도 풀 수 있다.
static int N, K;
static int v_list[10];
static int equation[10];
static void comb(int cnt, int v)
{
if (v == K)
{
for (int i = 1; i < cnt; i++)
printf("%d ", v_list[i]);
puts("");
return;
}
if (cnt > N)
return;
for (int i = 0; i <= K / equation[cnt]; i++)
{
int val = v + i * equation[cnt];
v_list[cnt] = i;
comb(cnt + 1, val);
}
}
int main()
{
N = 3; K = 6;
equation[1] = 1; equation[2] = 2; equation[3] = 1;
comb(1, 0);
}
equation 이라는 배열의 각 값은 해당 위치에 계수를 의미한다.
'알고리즘' 카테고리의 다른 글
최소 신장 트리 (0) | 2021.10.28 |
---|---|
같은 것이 있는 순열 (0) | 2021.10.28 |
이진 탐색 (0) | 2021.10.27 |
Graph, DFS and BFS (0) | 2021.10.27 |
병합정렬 (0) | 2021.10.27 |