순열이란 서로 다른 n개의 원소에서 r개를 뽑아 한 줄로 세우는 경우의 수를 말합니다.
C++에서는 next_permutation과 prev_permutation을 이용하여 이것을 손쉽게 구할 수 있습니다.
next_permutation
1) next_permutation의 사용방법
#include <algorithm>으로 algorithm 헤더파일을 추가하여야 합니다.
그리고 next_permutation에게 컨테이너의 시작과 끝 iterator를 인자로 전달하여 줍니다.
해당 컨테이너에 다음 순열이 존재하면 그 컨테이너의 다음 순열로 순서를 바꾸고 true를 반환합니다.
만약 다음 순열이 존재하지 않는다면 false를 반환합니다.
설명만으로는 이해하시기 어려울테니 예시를 들어서 설명을 드리겠습니다.
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main(void) {
vector <int> v;
// { 1, 2, 3, 4 } 저장
for (int i = 0; i < 4; i++)
v.push_back(i + 1);
do {
for (auto it = v.begin(); it != v.end(); ++it)
cout << *it << ' ';
cout << endl;
} while (next_permutation(v.begin(), v.end()));
return 0;
}
이렇게 하면 output이 다음과 같이 나오게 됩니다.
1 2 3 4
1 2 4 3
1 3 2 4
1 3 4 2
1 4 2 3
(생략)
4 2 3 1
4 3 1 2
4 3 2 1
오름차순으로 시작되었던 순열이 내림차순으로 끝났음을 알 수 있습니다.
그러면 비슷하지만 반대에 해당하는 연산인 prev_permutation에 대해서 알아보겠습니다.
prev_permutation
1) prev_permutation의 사용방법
next_permutation과 마찬가지로 algorithm 헤더파일을 추가하여야 합니다.
그리고 prev_permutation에게 컨테이너의 시작과 끝 iterator를 인자로 전달하여 줍니다.
해당 컨테이너에 이전 순열이 존재하면 그 컨테이너의 이전 순열로 순서를 바꾸고 true를 반환합니다.
만약 다음 순열이 존재하지 않는다면 false를 반환합니다.
예시를 들어보겠습니다.
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main(void) {
vector <int> v;
// { 4, 3, 2, 1 } 저장
for (int i = 0; i < 4; i++)
v.push_back(4 - i);
do {
for (auto it = v.begin(); it != v.end(); ++it)
cout << *it << ' ';
cout << endl;
} while (prev_permutation(v.begin(), v.end()));
return 0;
}
이렇게 하면 output이 다음과 같이 나오게 됩니다.
4 3 2 1
4 3 1 2
4 2 3 1
4 2 1 3
4 1 3 2
(생략)
1 3 2 4
1 2 4 3
1 2 3 4
내림차순으로 시작되었던 순열이 오름차순으로 끝났음을 알 수 있습니다.
추가
꼭 필요한 것은 아니지만 배울 것들이 몇 개 있어서 next_permutaion의 내부 알고리즘에 대해서 알아보겠습니다.
내부 알고리즘 코드를 보아도 이해하기가 어려웠는데 잘 소개가 된 블로그가 있어서 이곳을 참조하였습니다.
https://jeonggyun.tistory.com/110
next_permutation 알고리즘
c++ algorithm 라이브러리에서는 next_permutation 함수를 기본적으로 제공한다. 그 기능은 일반적인 순열의 순서로 배열 등의 순서를 바꾸어주고, 순열이 최종적으로 끝나면(완전히 역순이 되면) 다시
jeonggyun.tistory.com
단계는
1) 뒤에서부터 2개씩 숫자를 비교하여서 오름차순의 숫자 쌍을 찾습니다. ( {2,3}은 오름차순, {3,2}는 내림차순 )
2) 그 숫자 쌍에서 작은 숫자를 i로 그리고 큰 숫자를 k로 두겠습니다.
3) 이번에는 맨 뒤에서부터 j라는 인덱스로 i보다 큰 값을 갖는 위치에 j를 둡니다.
4) i와 j의 값을 바꾸어 줍니다.
5) k를 포함한 뒷부분을 순서를 뒤집어 줍니다(reverse)
위의 단계를 거쳐서 next_permutation을 진행시켜줍니다.
알고리즘 내에서 while문을 사용하여서 구현을 하였는데 그 부분을 잘 익혀두면 향후 코딩 문제를 푸는데에도 도움이 될 것 같습니다.
추가 2
next_permutation을 이용하여 combination을 구현한 신기한 코드를 보아서 추가하였습니다.
https://mjmjmj98.tistory.com/38
[C++ / Algorithm] 순열(next_permutation) 사용 방법과 조합(Combination) 구하기
순열을 구하는 next_permutation 함수 순열 수학적으로 순열(permutation)이란 서로 다른 n개의 원소에서 r개를 뽑아 한 줄로 세우는 경우의 수를 말합니다. 원소를 한 줄로 세우기 때문에 원소의 조합이
mjmjmj98.tistory.com
해당 블로그를 참조하였습니다.
Q : {1, 2, 3, 4} 중 2개의 원소를 고르는 모든 경우의 수 출력하기
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
vector<int> s{ 1, 2, 3, 4 };
vector<int> temp{ 1, 1, 0, 0 };
do {
for (int i = 0; i < s.size(); ++i) {
if (temp[i] == 1)
cout << s[i] << ' ';
}
cout << endl;
} while (prev_permutation(temp.begin(), temp.end()));
}
출처: https://mjmjmj98.tistory.com/38 [Live passionate😎]
temp라는 배열에 1 1 0 0 으로 각각 중복된 2개의 수를 가지도록 넣습니다.
그리고 1 1 0 0 을 prev_permutation을 이용해
1 1 0 0
1 0 1 0
1 0 0 1
0 1 1 0
0 1 0 1
0 0 1 1
로 만들어주고
각각 1일 때만 배열의 원소를 출력하면 combination을 구현할 수 있습니다.
permutation을 공부했어도 제 머리로는 위 알고리즘을 생각해내지 못 했을 것 같습니다..
이상으로 next, prev permutation에 대한 포스팅을 마치겠습니다.
'C++' 카테고리의 다른 글
C++ STL sort (0) | 2022.03.24 |
---|---|
C++ STL lower_bound, upper_bound (0) | 2022.03.23 |
C++ STL Iterator (0) | 2022.03.23 |
C++ STL Set (0) | 2022.03.22 |
C++ STL Map (0) | 2022.03.22 |