publicclassSubset_Visit{ staticint N, totalCnt; // 원소의 개수, 총 경우의 수 staticint[] inputs; staticboolean[] visit;
publicstaticvoidmain(String[] args){ // 부분 집합을 구하기 위해서 원소 입력 Scanner sc = new Scanner(System.in); N = sc.nextInt(); inputs = newint[N]; visit = newboolean[N]; for (int i = 0; i < N; i++) { inputs[i] = sc.nextInt(); }
// 부분집합 시작 getSubset(0);
// 출력 System.out.println("총 경우의 수 : " + totalCnt); }
privatestaticvoidgetSubset(int cnt){ // cnt가 원소의 개수만큼 돌았다면 if(cnt == N){ totalCnt++; for (int i = 0; i < N; i++) { // 선택된 배열과 선택되지 않은 배열 출력 System.out.print((visit[i] ? inputs[i] : "X") + "\t"); } System.out.println(); return; }
// 현재 원소를 선택하고 다음 visit[cnt] = true; getSubset(cnt+1);
// 현재 원소를 선택하지 않고 다음 visit[cnt] = false; getSubset(cnt+1); } }
위 코드를 실행해보면 아래와 같은 결과를 얻을 수 있습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
4 1 2 3 4 1 2 3 4 1 2 3 X 1 2 X 4 1 2 X X 1 X 3 4 1 X 3 X 1 X X 4 1 X X X X 2 3 4 X 2 3 X X 2 X 4 X 2 X X X X 3 4 X X 3 X X X X 4 X X X X 총 경우의 수 : 16
Subset 비트마스킹
위에서 봤던 방문배열을 사용하게 되면 원소의 개수가 커졌을 때, 메모리 사용량이 많이 들어갈 수 있습니다. 이번에는 비트마스킹을 이용해서 부분집합을 구해 보도록 하겠습니다.
publicclassSubset_Bitmask{ staticint N; // 원소의 개수 staticint[] inputs;
publicstaticvoidmain(String[] args){ // 부분 집합을 구하기 위해서 원소 입력 Scanner sc = new Scanner(System.in); N = sc.nextInt(); inputs = newint[N]; for (int i = 0; i < N; i++) { inputs[i] = sc.nextInt(); }
// 부분집합 시작 getSubset(1 << N);
// 출력 System.out.println("총 경우의 수 : " + (1 << N)); }
privatestaticvoidgetSubset(int cnt){ for (int flag = 0; flag < cnt; flag++) { // 0, 1, 2 ... flag 비트열 별로 원소 수만큼 각 자리 비트를 확인 for (int i = 0; i < N; i++) { System.out.print((((flag & (1 << i)) != 0) ? inputs[i] : "X") + "\t"); } System.out.println(); } } }
위 코드의 실행 원리를 예시를 들며 설명 하겠습니다.
2개의 원소가 있다고 가정하면 총 경우의 수는 4. 8을 Binary로 표현하면 1 0 0 이며, 4번을 돌며 각자리 입력 받은 원소의 개수만큼 비트 이동을 합니다.