완전 탐색 문제 중 재귀의 기본이 되는 순열 조합 부분집합에 대한 예시 코드 및 이론 정리
int n; // 숫자의 개수
int[] num; // 뽑은 숫자 배열
int[] arr; // 뽑을 숫자 배열
boolean[] used; // 방문 배열
public void permutation(int depth, int n) {
if (depth == n) {
System.out.println(Arrays.toString(num));
return;
}
for (int i = 0; i < n; i++) {
if (used[i]) {
continue;
}
num[depth] = arr[i];
used[i] = true;
permutation(depth + 1, n);
used[i] = false;
}
}
중복 순열은 방문 여부를 확인 할 필요가 없으므로, 순열을 구하는 코드에서 방문 배열 관련 코드를 제거하면 된다.
int n; // 숫자의 개수
int[] num; // 뽑은 숫자 배열
int[] arr; // 뽑을 숫자 배열
public void permutation(int depth, int n) {
if (depth == n) {
System.out.println(Arrays.toString(num));
return;
}
for (int i = 0; i < n; i++) {
num[depth] = arr[i];
permutation(depth + 1, n);
}
}
조합의 경우는 순열과 다르게 중복체크가 따로 필요없다. 호출하는 부분에서 i+1 로 값을 전달하기 때문에, 현재 값이 다시 사용되지 않는다.
int n; // 숫자의 개수
int[] num; // 뽑은 숫자 배열
int[] arr; // 뽑을 숫자 배열
public void combination(int depth, int now, int n) {
if (depth == n) {
System.out.println(Arrays.toString(num));
}
for (int i = now; i < n; i++) {
num[depth] = arr[i];
combination(depth+1, i+1);
}
}
중복 조합의 경우는 기존 조합 코드에서 단 한줄의 일부만이 달라진다.
중복 순열의 경우와 동일하게 중복체크 관련 부분이 달라진다.
int n; // 숫자의 개수
int[] num; // 뽑은 숫자 배열
int[] arr; // 뽑을 숫자 배열
public void combination(int depth, int now, int n) {
if (depth == n) {
System.out.println(Arrays.toString(num));
}
for (int i = now; i < n; i++) {
num[depth] = arr[i];
combination(depth+1, i); // 여기
}
}
int n; // 숫자의 개수
int[] arr; // 뽑을 숫자 배열
boolean[] used; // 방문배열
public void subset(int depth, n) {
if (depth == n) {
for (int i = 0; i < n; i++) {
if (used[i]) {
System.out.println(arr[i] + " ");
}
}
System.out.println();
return;
}
// 현재 위치의 숫자를 선택한 경우의 부분집합을 구함
used[depth] = true;
subset(depth+1, n);
// 현재 위치의 숫자를 선택하지 않은 경우의 부분집합을 구함
used[depth] = false;
subset(depth+1, n);
}