-

[C언어] 조합

Patti Smith 2022. 4. 2.

 

N개의 item에서 M개를 뽑고자 할 때 가능한 모든 방법을 출력하는 프로그램을 작성하시오.

 

다음과 같은 문제에서 뽑는 방법에 따라 여러가지 프로그램을 만들 수 있다.

뽑는 방법은 중복 여부/순서 고려에 따라 나눌 수 있고 그 경우는 다음과 같다.

 

- 중복 불가능

1. 조합(순서와 상관 없음)

2. 순열(순서와 상관 있음)

 

- 중복 가능(같은 item을 여러 번 뽑을 수 있음)

3. 중복 조합

4. 중복 순열

 

ex. 5개의 item에서 3개를 뽑고자 할 때 모든 방법을 사용하여 가짓수를 구하시오.

- 인덱스로 프로그램을 진행하므로 아이템의 내용물과 관계없이 순번으로 기입.

 

1. 조합 : 순서가 중요하지 않지만, 중복 없이 3개씩 뽑는다.

{0,1,2}

{0,1,3}

{0,1,4}

{0,2,3}

{0,2,4}

{1,2,3}

{1,2,4}

{1,3,4}

{2,3,4}

 

5C3 = 10

 

2. 중복 조합 : 순서가 중요하지 않지만, 중복하여 3개씩 뽑는다.

{0,0,0}

{0,0,1}

{0,0,2}

{0,0,3}

{0,0,4}

{0,1,0}

. .  

{3,4,4}

{4,4,4}

 

3. 중복 순열 : 순서가 중요하며, 중복하여 3개씩 뽑는다.

{0,0,0}

{0,0,1} 

{0,0,2}

{0,0,3}

{0,0,4}

{0,1,0}

{0,1,1}

{0,1,2}

{0,1,3}

{0,1,4}

...

 

5X5X5 = 125

 

4. 순열 : 순서가 중요하지만, 중복하지 않고 3개를 뽑는다.

{0,1,2}

{0,1,3}

{0,1,4}

{0,1,2}

{0,2,3}

{0,2,4}

{0,3,1}

{0,3,4}

{0,4,1}

{0,4,2}

{0,4,3}

{1,0,2}

...

 

5P3 = 5X4X3 = 60

 

문제 해결 방법

 

1. M개를 뽑아서 담을 수 있는 공간을 미리 할당 (buket)

 

2. 함수를 다음과 같이 구현.

pick(item 정보, buket 정보, k)

-k : 앞으로 뽑아야 할 크기

-trivial case (if k=0)

: M개를 뽑아야 할 문제인데 이미 M개를 다 뽑은 경우 적절한 일을 해주고 return한다. (무한 호출 막음)

-recurisve case (if k>0)

:앞으로 k를 뽑아야 하므로 일단 1개를 먼저 뽑고, 같은 함수를 이용하여 k-1개를 더 뽑는다.

:1개를 뽑는 방법은 순열/조합/중복순열/중복 조합에 따라 다름.

 

#1 조합(Combination)

void pick(int n, int* bucket, int buketSize, int k){

            int i, lastIndex, smallest, item;

            it(k==0){

                        for(i=0, i<buketSize; i++)

                                    printf("%d", buket[i]); // 4개 다 뽑았으면 printf

                        printf("\n");

                        return; // 무한 반복을 막기 위해 필수.

            }

            lastIndex = bucketSize - k -1;



            if (bucketSize == k) // 처음 뽑을 때

                        smallest = 0;

            else

                        smallest = bucket[lastIndex] + 1; // 최근에 뽑은 수 + 1 (오름차순)



            for(item = smallest; item<n; item++){

                        bucket[lastIndex+1] = item; // smallest ~ n까지 모든 경우의 수 구함.

                        pick(n,bucket,buketSize,k-1) // 나머지 자리수는 재귀함수를 불러 구함. 

            }

            return; // 생략 가능. item이 n이상일 경우 printf되지 않고 소멸.

}

 

#중복 조합(Combination with Repetition)

- 논리 흐름은 조합과 같지만, 중복 조합의 경우 오름차순으로 뽑을 때 본인 것까지 포함하여 뽑음

 

void pick(int n, int* bucket, int buketSize, int k){

            int i, lastIndex, smallest, item;

            it(k==0){
                        for(i=0, i<buketSize; i++)
                                    printf("%d", buket[i]); // 4개 다 뽑았으면 printf
                        printf("\n");
                        return; // 무한 반복을 막기 위해 필수.
            }

            lastIndex = bucketSize - k -1;

            if (bucketSize == k) // 처음 뽑을 때
                        smallest = 0;
            else
                        smallest = bucket[lastIndex]; // 최근에 뽑은 수(본인 것 포함/오름차순)

            for(item = smallest; item<n; item++){

                        bucket[lastIndex+1] = item; // smallest ~ n까지 모든 경우의 수 구함.
                        pick(n,bucket,buketSize,k-1) // 나머지 자리수는 재귀함수를 불러 구함. 

            }
            return; // 생략 가능. item이 n이상일 경우 printf되지 않고 소멸.
}

#중복순열(Permutation with Repetition)

- 새 item을 뽑을 때 매번 전체 아이템 중에서 뽑음.

 

void pick(int n, int* bucket, int buketSize, int k){

            int i, lastIndex, smallest, item;

            it(k==0){

                        for(i=0, i<buketSize; i++)

                                    printf("%d", buket[i]); // 4개 다 뽑았으면 printf

                        printf("\n");

                        return; // 무한 반복을 막기 위해 필수.

            }

            lastIndex = bucketSize - k -1;



            smallest = 0; // 전체 아이템에서 뽑음.



            for(item = smallest; item<n; item++){

                        bucket[lastIndex+1] = item; // smallest ~ n까지 모든 경우의 수 구함.

                        pick(n,bucket,buketSize,k-1) // 나머지 자리수는 재귀함수를 불러 구함. 

            }

            return; // 생략 가능. item이 n이상일 경우 printf되지 않고 소멸.

}

#순열(Permutation)

 

void pick(int n, int* bucket, int buketSize, int k){

            int i, lastIndex, smallest, item;

            it(k==0){

                        for(i=0, i<buketSize; i++)

                                    printf("%d", buket[i]); // 4개 다 뽑았으면 printf

                        printf("\n");

                        return; // 무한 반복을 막기 위해 필수.

            }

            lastIndex = bucketSize - k -1;



            smallest = 0; // 전체 아이템에서 뽑음. 단, 안 뽑힌 아이템 중에서 뽑는다.



            for(item = smallest; item<n; item++){

                        int choose = 0;

                        // choose로 뽑힌 아이템들 중 중복되는 게 있는지 확인. 

                        for(int i=0; i<lastIndex+1; i++)

                                    if(item == bucket[i]){

                                                choose = 1;

                                                break;

                                    }

                        // 중복되는 게 없는 경우 해당 순번 아이템을 bucket에다가 넣음.

                        if(choose==0){     

                                    bucket[lastIndex+1] = item; 

                                    pick(n,bucket,buketSize,k-1) 

                        }

            }

}

 

 

 

 

'-' 카테고리의 다른 글

[자료구조] 과제 1주차  (0) 2022.09.07
2차원 포인터  (0) 2022.05.10
7일간 진행했던 교내 해커톤 후기  (0) 2022.03.05
document 객체  (0) 2021.12.12
파일 입출력  (0) 2021.11.30

댓글