본문 바로가기

공부/알고리즘

[완전탐색/순열] 재귀 함수로 순열을 짜보자! (크기 순서로)

반응형

재귀함수를 통해 순열을 짜는 방법을 알아보겠습니다.

우선 예제로 주어진 수가 1 2 3 4 5일 때 을 구해봅시다. 


어떻게하면 순열을 구할 수 있을까요?


바로, 앞의 3 자리를 순열의 결과로 보는 것입니다.

보통 결과를 앞에 3자리에 위치시키기 위해 크게 2가지 방법이 있습니다.


1. swap을 이용한 방법

2. 오른쪽으로 한칸씩 원형 회전 시키는 방법


1번의 경우에는 순열을 구하는 순서가 상관이 없을 때 사용합니다.

2번의 경우는 순열을 구하는 순서가 정해져 있는 경우입니다. (특히 크기 순서로)


1번을 예로 보겠습니다.

1 2 3 4 5가 있을 때,

맨 앞자리를 처음에는 1로 한다.

그리고 다음 2번째 수를 2로 하고,

3번째 수를 3으로 하면, 1 2 3 순열이 만들어집니다.

이제 3과 4를 swap해서 1 2 4 (3 5)가 되고, 1 2 4 순열이 만들어집니다.

다음은 1 2 5  순열을 만들 수 있습니다!


이제 더이상 swap을 할 수 없기 때문에 다시 이전으로 돌아가게 되고, 이번에는 2와 3을 swap하여 1 3 2 4 5 배열을 만듭니다.

이제 다시 위에서 했던 과정을 통해 1 3 2, 1 3 4, 1 3 5 순열을 만들 수 있습니다.


그리고 다음에는 1 4 3 2 5 배열이 되고, 1 4 3, 1 4 2, 1 4 5 순열을 만들 수 있습니다.


여기서 1 4 3, 1 4 2 순서로 순열이 전개가 되는 것을 확인할 수 있습니다.

하지만, 1 4 3, 1 4 2는 순서에 맞지 않습니다! 바로 swap을 이용했기 때문에 배열의 정렬이 깨졌기 때문입니다.

만약 순열의 순서가 중요하다면 (특히 정렬된 상태로) 오른쪽으로 한칸 회전 시키는 방법을 이용합니다.


왜 오른쪽으로 한 칸 회전 하면 이 현상을 해결할 수 있을까요? 


다시 한 번 1 4 가 되는 경우를 예로 들겠습니다!


1 2 3 4 5 배열에서 1 (2 3 4) 5 괄호친 2 3 4 부분을 한칸씩 오른쪽으로 돌려봅시다.

그러면, 1 4 2 3 5 가 됩니다. 이렇게 하면 1 4 (2 3 5) 4 뒷 부분이 정렬된 상태로 여전히 존재하는 것을 알 수 있습니다.


이렇게 해서 1 4 2을 얻고,

1 4 (2 3) 5 를 오른쪽으로 한칸 회전해서 1 4 3 2 5 즉, 1 4 3 순열을 얻을 수 있는 것입니다.

다음은 1 4 (2 3 5) -> 1 4 5 2 3 이 되고, 1 4 5 순열을 얻습니다.

이를 통해 크기 순서에 맞게 순열을 얻을 수 있습니다.


만약, 순열 문제를 풀고 싶다면 백준 사이트에서 만날 수 있는 N과 M 문제를 추천드립니다.

무려 N과 M이 12번 까지 있습니다. 이것들만 푼다면, 순열과 조합은 완! 벽!하게 마스터 했다고 봐도 좋을 것입니다!


N과 M (1)



아래는 순열 소스코드이다. rightR()과 leftR()을 swap으로 바꾸기만 하면 1번 형식으로 변환할 수 있습니다.

 

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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
#include<iostream>
#include<cstring>
#include<queue>
#include<vector>
#include<algorithm>
 
using namespace std;
 
void rotateR(int,int);
void rotateL(int,int);
 
int arr[8];
 
void print(int n)
{
    for(int i = 0; i < n; i++)
    {
        cout << arr[i] << ' ';
    }
    cout << '\n';
}
 
void permutation(int n, int r, int length)
{
    if(length == r)
    {
        print(r);
    }
 
    for(int i = length; i < n; i++)
    {
        rotateR(length,i);
        permutation(n,r, length+1);
        rotateL(length,i);
    }
}
 
void rotateR(int st, int dt)
{
    int temp = arr[dt];
    for(int i = dt; i > st; i--)
    {
        arr[i] = arr[i-1];
    }
    arr[st] = temp;
}
 
void rotateL(int st, int dt)
{
    int temp = arr[st];
    for(int i = st; i < dt; i++)
    {
        arr[i] = arr[i+1];
    }
    arr[dt] = temp;
}
 
int main ()
{
    
    priority_queue<intvector<int>, greater<int> > que;
    int n,r;
    cin >> n >> r;
 
    int in;
    for(int i = 0; i < n; i++)
    {
        cin >> in;
        que.push(in);
    }
    in = 0;
 
    while(que.size())
    {
        arr[in++= que.top();
        que.pop();
    }
 
    permutation(n,r,0);
 
    return 0;
}
cs


반응형