알고리즘
부분집합
코딩 화이팅
2023. 3. 21. 14:25
부분집합의 수
- 집합의 원소가 n개일 때, 공집합을 포함한 부분집합의 수는 2^n개이다.
- 이는 각 원소를 부분집합에 포함시키거나 포함시키지 않는 2가지 경우를 모든 원소에 적용한 경우의 수와 같다
반복문을 이용한 부분집합 구하기
package day0321_부분집합_조합;
import java.util.Arrays;
public class 부분집합_1 {
String[] 재료 = {"참치", "우엉", "삼겹살"};
public static void main(String[] args) {
//반복문을 이용해서 부분집합을 구해보자.
int N = 3;
int[] sel = new int[N];
for(int i = 0 ; i<2; i++) {
sel[0] = i;
for(int j = 0; j<2; j++ ) {
sel[1] = j;
for(int k = 0 ; k<2; k++) {
sel[2] = k;
System.out.println(Arrays.toString(sel));
}
}
}
}
}
//
[0, 0, 0]
[0, 0, 1]
[0, 1, 0]
[0, 1, 1]
[1, 0, 0]
[1, 0, 1]
[1, 1, 0]
[1, 1, 1]
비트마스킹을 이용한 부분집합 구하기
package day0321_부분집합_조합;
public class 부분집합_2 {
static String[] 재료 = {"참치", "우엉", "삼겹살"};
public static void main(String[] args) {
//비트마스킹을 이용해보자
int N = 3;
//i는 모든 부분집합을 의미한다.
for(int i = 0 ; i<(1<<N); i++) {
//i가 부분집합 중 1개라는 것은 알겠어.
//그런데 i가 무슨 원소를 가진 부분집합인지는 몰라
//i가 무슨 원소를 가진 부분집합인지 검사를 해야해.
//N개의 원소를 검사를 한다.
String tmp = "";
for(int j = 0 ; j < N; j++) {
//i의 j번째 비트에 해당 값이 있는지 쳌
// if((i & (1<<j)) != 0) {
if((i & (1<<j)) > 0) {
//해당 j번째의 요소가 이번 부분집합에는 포함되어 있습니다.
tmp+=재료[j];
}
}
System.out.println(tmp);
}
}
}
//
(충무김밥)
참치
우엉
참치우엉
삼겹살
참치삼겹살
우엉삼겹살
참치우엉삼겹살
재귀를 이용한 부분집합
package day0321_부분집합_조합;
public class 부분집합_3 {
static String[] 재료 = {"참치", "우엉", "삼겹살"};
static int N;
static boolean[] sel ; //해당 요소 선택 했다!
public static void main(String[] args) {
N = 3;
sel = new boolean[N];
powerset(0);
}
//메소드를 작성할때 최대한 파라미터를 심플하게
//idx : 해당 원소를 포함할지 안할지를 결정해야함.
public static void powerset(int idx) {
//base case : 재귀를 빠져 나갈 수 있는 조건
//모든 재료를 넣을지 / 말지 에 대한 판단 끝났어!
if(idx==N) {
String tmp = "";
for(int i = 0 ; i<N; i++) {
if(sel[i])
tmp+=재료[i];
}
System.out.println(tmp);
return;
}
//recursive : 나 자신을 다시 호출하는 조건
sel[idx] = true; //idx번째의 재료를 사용했어!
powerset(idx+1); //다음 재료를 고려해~
sel[idx] = false; //idx번째의 재료를 사용하지 않았어!
powerset(idx+1); //다음 재료를 고려해~
}
}
//
참치우엉삼겹살
참치우엉
참치삼겹살
참치
우엉삼겹살
우엉
삼겹살
(충무김밥)
재귀를 이용한 부분조합
package day0321_부분집합_조합;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class 조합_1 {
//재귀를 이용해서 조합을 만들어보자.
static String[] 토핑 = {"상추", "패티", "토마토", "치즈"};
static int N = 4;
static int R = 2; // 문제에서 이런것들은 다 주어짐.
static String[] sel = new String[R]; //내가 선택한 토픵
static List<String[]> list = new ArrayList<>();
public static void main(String[] args) {
combination(0, 0);
}
//idx : 내가 이번 깊이에서 고려할 재료!
//sidx : 현재 뽑을 자리
public static void combination(int idx, int sidx) {
//base case
if(sidx == R) {//다 뽑았어
System.out.println(Arrays.toString(sel));
return;
}
//recursive case
//경계값 결정
for(int i = idx ; i<= N-R+sidx; i++) {
sel[sidx] = 토핑[i];
combination(i+1, sidx+1);
}
}
}
//
[상추, 패티]
[상추, 토마토]
[상추, 치즈]
[패티, 토마토]
[패티, 치즈]
[토마토, 치즈]
package day0321_부분집합_조합;
import java.util.Arrays;
public class 조합_2 {
//재귀를 이용해서 조합을 만들어보자.
static String[] 토핑 = {"상추", "패티", "토마토", "치즈"};
static int N = 4;
static int R = 2; // 문제에서 이런것들은 다 주어짐.
static String[] sel = new String[R]; //내가 선택한 토픵
public static void main(String[] args) {
combination(0, 0);
}
//idx : 내가 이번 깊이에서 고려할 재료!
//sidx : 현재 뽑을 자리
public static void combination(int idx, int sidx) {
//base case
if(sidx == R) {//다 뽑았어
System.out.println(Arrays.toString(sel));
return;
}
if(idx == N) { //고려 다했어.
return;
}
//recursive case
sel[sidx] = 토핑[idx]; //sidx 자리에 현재 보고있는 idx 토핑을 저장할래
combination(idx+1, sidx+1); //이번 재료 썼고, 다음재료 판단하러가보자.
combination(idx+1, sidx); //이번 재료 안썼고, 다음재료 판단하러가보자.
}
}
//
[상추, 패티]
[상추, 토마토]
[상추, 치즈]
[패티, 토마토]
[패티, 치즈]
[토마토, 치즈]