ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 순열과 조합
    잡다한 지식 2020. 3. 18. 19:49

    백준 문제를 풀면서 stl을 사용하지 않고, 재귀적 방법으로 순열과 조합을 구현해서 문제를 풀어야하는 경우가 많았기에 정리해서 올려본다.


    순열

    • 개념 : 서로 다른 n개의 원소에서 r개를 중복없이 골라 순서에 상관있게 나열하는 것 (nPr)
    • 예시 : 

    [1, 2, 3, 4, 5] 5개의 원소 중에서 3개를 고르시요.


    답)

    맨 앞자리가 1일 경우 : [1,2,3], [1,2,4], [1,2,5], [1,3,2], [1,3,4], [1,3,5], [1,4,2], [1,4,3], [1,4,5], [1,5,2], [1,5,3], [1,5,4]

    맨 앞자리가 2일 경우 : [2,1,3], [2,1,4], [2,1,5], [2,3,1], [2,3,4], [2,3,5], [2,4,1], [2,4,3], [2,4,5], [2,5,1], [2,5,3], [2,5,4]

    ... 이런식으로 많은 경우의 수가 나올수 있다. 

    • 소스 코드 구현

    위에서 예시로 든 5개중에서 3개를 고르는 코드를 구현하자면


    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
    #include <stdio.h>
    #include <vector>
    using namespace std;
     
    bool visited[6]; //이미 고른 숫자를 제외해주는 배열
    vector <int> temp; //3개를 잘 골랐나 출력해주는 함수
     
    //cnt - 몇개까지 골랐는지 알려주는 변수 = dfs함수의 depth
    void dfs(int cnt) {
        if (cnt == 3) {
            for (int i = 0; i < 3; i++) {
                printf("%d ", temp[i]);
            }
            printf("\n");
            return// return을 해줘야 3개를 이미 고른 상태에서 끝남
        }
        for (int i = 1; i <= 5; i++) { // 시작원소가 2라도 1을 봐야하므로 for문을 1부터 시작한다.
            if (visited[i] == truecontinue
            
            //이전에 고르지 않았다면
            visited[i] = true//골랐음을 표시
            temp.push_back(i);
            dfs(cnt + 1); //다른 원소를 뽑기 위해 다시 dfs호출
     
            //dfs갔다와서
            temp.pop_back();
            visited[i] = false;
        }
    }
     
    int main(void)
    {
        dfs(0);
    }
    cs




    조합

    • 개념 : 서로 다른 n개의 원소 중에서 순서에 상관없이 r개를 선택하는 것 (nCr)
    • 예시 : 

    [1, 2, 3, 4, 5] 5개의 원소 중에서 3개를 뽑으시오.


    답) [1,2,3], [1,2,4], [1,2,5], [2,3,4], [2,3,5], [3,4,5] 


    → 규칙을 생각해보면, 시작원소가 1일때 모든원소를 보지만, 시작 원소가 2일때는 1을 제외하고 보고, 

       시작 원소가 3일때는 1, 2를 제외하고 본다.


    • 소스 코드 구현

    위에서 예시로 든 5개중에 3개를 뽑는 코드를 구현하자면


    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
    #include <stdio.h>
    #include <vector>
    using namespace std;
     
    bool visited[6]; //이미 고른 숫자를 제외해주는 배열
    vector <int> temp; //3개를 잘 골랐나 출력해주는 함수
     
    //idx - 시작 원소를 알려주는 변수, cnt - 몇개까지 골랐는지 알려주는 변수 = dfs함수의 depth
    void dfs(int idx, int cnt) {
        if (cnt == 3) {
            for (int i = 0; i < 3; i++) {
                printf("%d ", temp[i]);
            }
            printf("\n");
            return// return을 해줘야 3개를 이미 고른 상태에서 끝남
        }
        for (int i = idx; i <= 5; i++) {
            if (visited[i] == truecontinue//이미 이전에 고른 원소라면, 넘어감
            
            //이전에 고르지 않았다면
            visited[i] = true//골랐음을 표시
            temp.push_back(i);
            dfs(i, cnt + 1); //다른 원소를 뽑기 위해 다시 dfs호출
     
            //dfs갔다와서
            temp.pop_back();
            visited[i] = false;
        }
    }
     
    int main(void)
    {
        dfs(10);
    }
     
    cs
                                                               ★idx와 cnt를 주의깊게 봐야한다.

    결과값 -  으로 잘 나오는 것을 확인할 수 있다.




    만일, 중복순열과 중복조합을 만들고 싶다면

    이미 사용했던 원소도 다시 사용할 수 있으므로, visited[]함수를 제외하고 코드를 작성하면 된다.


    '잡다한 지식' 카테고리의 다른 글

    bit-mask  (0) 2020.04.04
    복잡도 표기법  (0) 2020.03.27
    sort 함수 사용법  (0) 2020.03.25
    next_permutaion 함수  (0) 2020.03.18
    자료형  (0) 2020.03.16

    댓글

Designed by Tistory.