C++

std::next_permutation() 사용법 정리

2023. 1. 25. 14:01
목차
  1. std::next_permutation()
  2. $ {}_n \mathrm{P}_n $ 순열 출력
  3. $ {}_n \mathrm{P}_r $ 순열 출력
  4. $ {}_n \mathrm{C}_r $ 조합 출력
728x90

std::next_permutation()

입력받은 원소의 다음 순열을 구함
다음 순열이 존재하면 true, 존재하지 않으면 false를 반환

$ {}_n \mathrm{P}_n $ 순열 출력

#include <iostream>
#include <algorithm>
#define N 4

int main(void) {
    int arr[N] = { 1, 2, 3, 4 };
    do {
        for (int i = 0; i < N; i++) {
            std::cout << arr[i] << " ";
        }
        std::cout << "\n";
    } while (std::next_permutation(arr, arr + N));
    return 0;
}

// output
// 1 2 3 4
// 1 2 4 3
// 1 3 2 4
// ...
// 4 3 1 2
// 4 3 2 1

$ {}_n \mathrm{P}_r $ 순열 출력

#include <iostream>
#include <algorithm>
#define N 4
#define R 2

int main(void) {
    int arr[N] = { 1, 2, 3, 4 };
    do {
        for (int i = 0; i < R; i++) {
            std::cout << arr[i] << " ";
        }
        std::cout << "\n";
        std::reverse(arr + R, arr + N);
    } while (std::next_permutation(arr, arr + N));
    return 0;
}

// output
// 1 2 
// 1 3
// 1 4
// ...
// 4 2
// 4 3

std::reverse() 함수를 사용하지 않고 결과를 출력하면 다음과 같이 같은 순열이 중복되어 출력된다.

// * WRONG *
// 1 2 
// 1 2
// 1 3
// 1 3
// ...
// 4 2
// 4 2
// 4 3
// 4 3

그 이유를 살펴보면, 우리는 앞에서부터 $ r $개의 원소만 필요한 데 반해 std::next_permutation() 함수는 모든 $ n $개의 원소의 순열을 구하기 때문이다. 예시로 든 $ n = 4 $, $ r = 2 $ 의 경우를 살펴보자. 밑의 코드 블럭에서 | 앞의 숫자들이 우리 눈에 보이는 결과물인데, 내부적으로는 4개의 원소를 전부 정렬하지만 출력은 앞에서부터 2개의 원소만 되기 때문에 마치 같은 순열이 중복된 것처럼 보인다.

// 1 2 | 3 4
// 1 2 | 4 3
// 1 3 | 2 4
// 1 3 | 4 2
// 1 4 | 2 3
// 1 4 | 3 2
// ...

그렇다면 왜 std::reverse() 함수를 사용하면 문제를 해결할 수 있을까? $ n = 5 $, $ r = 2 $ 일 때 std::next_permutation()을 통해 다음과 같은 순열을 구한 상태를 가정하자.

이 순열 중 우리가 필요한 $ 1 $번째 ~ $ r $번째 숫자들을 $ A $, $ r + 1$번째 ~ $ n $번째 숫자들을 $ B $ 라고 하자. 이때 $ B $로 이루어진 순열을 사전순으로 정렬하면 다음과 같다.

위 결과에서 $ B $의 첫번째 순열을 뒤집으면 제일 마지막 순열이 된다는 사실을 관찰할 수 있다. 즉

이 상태에서 $ B $를 뒤집고

std::next_permutation() 함수를 실행하면

바로 우리가 필요한 다음 순열로 넘어갈 수 있다.

$ {}_n \mathrm{C}_r $ 조합 출력

#include <iostream>
#include <algorithm>
#define N 4
#define R 2

int main(void) {
    int arr[N] = { 1, 2, 3, 4 };
    int sel[N] = { 0, 0, 1, 1 };
    do {
        for (int i = 0; i < N; i++) {
        	if (sel[i] == 0) std::cout << arr[i] << " ";
        }
        std::cout << "\n";
    } while (std::next_permutation(sel, sel + N));
    return 0;
}

// output
// 1 2 
// 1 3
// 1 4
// 2 3
// 2 4
// 3 4

백트래킹 알고리즘을 통해 조합을 구할 때를 생각하면 된다. 주어진 데이터와 별개로 '선택 배열'을 하나 만들어서 데이터를 선택하는 모든 경우의 수를 구하면 된다. 주의할 점은 선택할 데이터를 $ 0 $, 선택하지 않을 데이터를 $ 1 $로 설정해야 한다. std::next_permutation() 함수는 오름차순으로 순열을 구하므로 선택할 데이터를 나타내는 값이 선택하지 않을 데이터의 값보다 크면 정상적으로 동작하지 않는다.

'C++' 카테고리의 다른 글

자주 사용하는 STL 정리  (0) 2022.09.23
  • std::next_permutation()
  • $ {}_n \mathrm{P}_n $ 순열 출력
  • $ {}_n \mathrm{P}_r $ 순열 출력
  • $ {}_n \mathrm{C}_r $ 조합 출력
'C++' 카테고리의 다른 글
  • 자주 사용하는 STL 정리
Park Joonyoung
Park Joonyoung
개발 블로그
DevJoon개발 블로그
Park Joonyoung
DevJoon
Park Joonyoung
전체
오늘
어제
  • 분류 전체보기 (88)
    • BOJ (41)
      • 틀렸습니다 (6)
    • 알고리즘 (4)
    • C++ (2)
    • Python (1)
    • 토이 프로젝트 (0)
    • 선형대수학 (1)
    • 기타 (3)
    • 에세이 (4)
    • [개인 보관용] (32)
      • 이코테 강의 정리 (0)
      • 알고리즘(old) (0)
      • 단변수미적분학 (0)
      • 다변수미적분학 (0)
      • 선형대수학 (32)
      • 선형대수학(old) (0)
      • 프랑스어 (0)
      • 독서노트 (0)
      • 사진 (0)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • github
  • ps
  • 백트래킹
  • 에세이
  • bfs
  • 구현
  • Notion
  • It
  • BOJ
  • 그리디
  • 수학
  • Python
  • DP
  • c++
  • 백준
  • stl
  • dfs
  • 시뮬레이션
  • 개발
  • 선형대수학
  • 알고리즘
  • git bash
  • next_permutation
  • 코딩테스트
  • 브루트포스
  • DevJoon

최근 댓글

최근 글

hELLO · Designed By 정상우.
Park Joonyoung
std::next_permutation() 사용법 정리
상단으로

티스토리툴바

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.