티스토리 뷰

알고리즘/브루트포스

C++ 10972 다음 순열

신입사원 성장기 2023. 7. 29. 12:38

https://www.acmicpc.net/problem/10972

 

10972번: 다음 순열

첫째 줄에 입력으로 주어진 순열의 다음에 오는 순열을 출력한다. 만약, 사전순으로 마지막에 오는 순열인 경우에는 -1을 출력한다.

www.acmicpc.net

 

처음에는 브루트포스로 모든 순열을 순서대로 조사한 후 같은 순열이 나오면 그 다음 순열을 출력하는 방식으로 풀이하였다.

#include <bits/stdc++.h>
using namespace std;
int n;
bool vis[10001];
int arr[10001];
int sortedArr[10001];
vector<int> vec;
bool flag;

void dfs(int k) {
    if(k == n) {
        if(flag) {
            for (const auto &v: vec) {
                cout << v << ' ';
            }
            exit(0);
        }

        for(int i=0; i<n; i++) {
            if(arr[i] != vec[i])
                return;
        }
        flag = true;
        return;
    }

    for(int i=0; i<n; i++) {
        if(vis[sortedArr[i]]) continue;
        vis[sortedArr[i]] = true;
        vec.push_back(sortedArr[i]);
        dfs(k+1);
        vis[sortedArr[i]] = false;
        vec.pop_back();
    }
}

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);

    cin >> n;
    for(int i=0; i<n; i++) {
        cin >> arr[i];
        sortedArr[i] = arr[i];
    }
    sort(sortedArr, sortedArr+n);
    dfs(0);
    cout << -1;
}

당연히 이렇게 풀면 O(n!)이므로 시간 초과가 뜬다. 하지만 다른 방법이 생각나지 않았다.

 

다음과 같이 순열을 나열하는 규칙을 이용하여 풀 수 있다.

풀이

1. 뒤에서부터 시작하여 오름차순이 끊기는 지점 찾기

2. 끊기는 지점 뒤에서, 끊기는 지점보다 처음으로 큰 원소를 찾아서 교환

3. 끊기는 지점 뒤의 원소의 순서를 바꿔 준다.

 

예시를 들면 다음과 같다.

결과적으로 1 2 3 6 5 4의 다음 순열은 1 2 4 3 5 6이 된다.


코드

#include <bits/stdc++.h>
using namespace std;
int n;
int arr[10001];

bool next_permutation() {
    int i = n-1;
    while(i > 0 && arr[i-1] > arr[i]) {
        i--;
    }
    if(i == 0) {
        return false;
    }
    int j = n-1;
    while(i-1 < j && arr[i-1] > arr[j])    j--;
    swap(arr[i-1], arr[j]);

    j = n-1;
    while(j > i) {
        swap(arr[i], arr[j]);
        i++;
        j--;
    }
    return true;
}

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);

    cin >> n;
    for (int i = 0; i < n; i++)
        cin >> arr[i];

    if (next_permutation()) {
        for (int i = 0; i < n; i++) {
            cout << arr[i] << ' ';
        }
    }
    else{
        cout << -1;
    }
}

시간 복잡도는 O(N)

 

참고로 STL next_permutation이라는게 존재해서 배열의 시작주소와 끝 주소를 넣어주면, 다음 순열을 찾아준다.

#include <bits/stdc++.h>
using namespace std;
int n;
int arr[10001];

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);

    cin >> n;
    for (int i = 0; i < n; i++)
        cin >> arr[i];

    if (next_permutation(arr, arr+n)) {
        for (int i = 0; i < n; i++) {
            cout << arr[i] << ' ';
        }
    }
    else {
        cout << -1;
    }
}

간단하게 풀 수 있다. 

'알고리즘 > 브루트포스' 카테고리의 다른 글

C++ 1248 Guess  (0) 2023.07.31
C++ 14501 퇴사  (0) 2023.07.29
C++ 1748 수 이어 쓰기 1  (0) 2023.07.27
C++ 14500 테트로미노  (0) 2023.07.24
C++ 백준 1107 리모컨  (0) 2023.07.23
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday