멱집합 (powerset)
의미
- 어떤 집합의 모든 부분집합들의 집합이다.
- data = {a, b, c, d}의 모든 부분집합을 출력한다면(멱집합)
∅, a, b, c, d, ab, ac, ad, bc, bd, cd, abc, abd, acd, bcd, abcd가 있다.
이는 $2^4$개로서 총 16개라 할 수 있다.
멱집합을 구하는 방법
- {a, b, c, d, e, f}의 모든 부분집합을 나열하고자 한다.
1) a를 제외한 {b, c, d, e, f}의 모든 부분집합들을 나열한다.
2) {b, c, d, e, f}의 모든 부분집합에 {a}를 추가한 집합들을 나열한다.
-이는 곧 a를 포함하지 않은 부분집합의 수인 $2^5$와 포함한 부분집합의 수인 $2^5$가 합해져 총 $2^6$개가 된다.
- {b, c, d ,e, f}의 모든 부분집합에 {a}를 추가한 집합들을 나열한다 할 때
1) {c, d, e, f}의 모든 부분집합에 {a}를 추가한 집합들을 나열한다.
2) {c, d, e, f}의 모든 부분집합에 {a, b}를 추가한 집합들을 나열한다.
- 이 방법을 recursive하게 계속 반복하게 된다면 결국 원하는 결과를 얻을 수 있게 된다.
슈도 코드
powerSet (S)
if S is an empty set //S가 공집합이라면
print nothing;
else
let t be the first element of S; //집합에서의 한 원소 t를 고른다.
find all subsets of S - {t} by calling powerSet(S - {t}); //t를 제외한 모든 부분집합을 구한다.
print the subsets;
print the subsets with adding t;
-> 이 슈도 코드에서의 powerSet함수는 여러 개의 집합들을 반환해야 한다.
-개선
powerSet (P, S) //초기값은 powerSet (∅, data);로 주어 시작하면 된다.
if S is an empty set
print P;
else
let t be the first element of S;
powerSet (P, S - {t}); //t를 포함하지 않은 집합
powerSet (P ∪ {t}, S - {t}); //t를 포함한 집합
-> 이 슈도코드에서는 순환함수가 두 개의 집합을 별도의 매개변수로 받도록 설계하였다.
-> 두 번째 집합의 모든 부분집합에 첫 번째 집합을 합집합한 후 출력을 한다.
- 위 슈도코드에 따라 {b, c, d, e, f}의 모든 부분집합에 {a}를 추가한다 하였을 때
{c, d, e, f}가 S로 k번째부터 마지막 원소까지 연속된 원소들이다.
{a, b}를 추가한 집합들이나 {a}를 추가한 집합들이 P라 할수 있으며 처음부터 k - 1번째 원소들 중 일부이다.
- 집합 S는 k번째 인덱스 이후 마지막 인덱스인 n - 1번째 인덱스까지의 집합이다.
- P는 k번째 인덱스 앞의 원소들 중 일부인데 이를 표시하기 위해서는 include함수를 통해 true / false로 구분한다. 또한 include함수에서의 true반환 인덱스들의 집합이다.
구현
private static char data[] = {'a', 'b', 'c', 'd', 'e', 'f'};
private static int n = data.length;
private static boolean[] include = new boolean[n]; //트리상에서 현재의 위치를 표시한다.
public static void powerSet (int k) { //k또한 트리상에서 현재 위치를 표시한다.
if (k == n) { //만일 위치가 리프 노드라면
for (int i = 0; i < n; i++)
if (include[i])
System.out.println(data[i] + " ");
System.out.println();
return;
}
include[k] = false;
powerSet (k + 1); //왼쪽으로 먼저 내려간다.
include[k] = true;
powerSet (k + 1); //오른쪽으로 내려간다.
}
-> 이 프로그램을 실행할 때는 초기값을 powerSet(0)으로 실행하여 P를 공집합으로, S를 전체집합으로 설정한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.InputStreamReader; import java.io.OutputStreamWriter; public class PowerSetProblem { static char data[]; //멱집합을 구하고자 하는 배열 static int n; //데이터배열의 총 길이를 나타내는 변수 static boolean[] includes; //P의 원소를 가리켜주는 배열 static BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out)); public static void main (String[] args) throws Exception { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); bw.write("멱집합을 구하고자 하는 문자들을 입력해주세요(띄어쓰기 없이) : "); bw.flush(); String input = br.readLine(); data = input.toCharArray(); n = data.length; includes = new boolean[n]; powerSet(0); bw.close(); } static void powerSet (int k) throws Exception { if (k == n) { for (int i = 0; i < n; i++) if (includes[i]) bw.write(String.valueOf(data[i]) + " "); bw.write("\n"); bw.flush(); return; } includes[k] = false; powerSet(k + 1); includes[k] = true; powerSet(k + 1); } } | cs |
'프로그래밍 > 알고리즘' 카테고리의 다른 글
정렬 알고리즘 - 합병 정렬 (0) | 2019.05.20 |
---|---|
기초 정렬 알고리즘 (0) | 2019.05.18 |
Recursion 응용(3) (0) | 2019.05.14 |
Recursion 응용(2) (0) | 2019.05.12 |
Recursion 응용(1) (0) | 2019.05.10 |