Algorithm/코딩 테스트 준비 - 기초
[코딩 테스트 준비 - 기초] 6. 브루트 포스 - 순열
반응형
1. 다음(이전) 순열 구하기
- 순열은 순서가 중요한 경우 사용한다.
- 순열을 사전순으로 나열했을 때, 첫 순열은 배열을 오름차순 정렬한 것이고, 마지막 순열은 내림자순 정렬한 것이다.
- 다음 순열이란 i번째 순열이 주어진 경우 i+1번째 순열을 의미한다. (이전 순열은 반대)
- 시간복잡도는 배열의 크기가 N인 경우
O(N * N!)
이다. 따라서N<=10
인 경우1초
내에 들어온다.
C++에서는 다음 순열(next_permutation
)과 이전 순열(prev_permutation
)을 구하는 STL이 있다.
algorithm
헤더에 있다.- 다음(이전) 순열이 있는 경우
true
를, 그렇지 않은 경우false
를 반환한다. - 첫 번째 인자로 배열의 시작을, 두 번째 인자로 배열의 마지막을 넣어준다.
- 이를 이용해 모든 순열을 구하기 위해서는 정렬을 해줘야 한다.
- 오름차순 정렬 -> 다음 순열 이용
- 내림차순 정렬 -> 이전 순열 이용
[백준 10972 다음 순열 & 백준 10973 이전 순열]
#include <iostream>
#include <algorithm>
using namespace std;
int main() {
int n;
cin>>n;
int arr[n];
for(int i=0; i<n; i++)
cin>>arr[i];
if(next_permutation(arr, arr + n)){ //이전 순열: prev_permutation
for(int i=0; i<n; i++)
cout<<arr[i]<<" ";
} else{
cout<<-1;
}
cout<<'\n';
return 0;
}
[백준 10974 모든 순열]
- 첫 순열로 먼저 출력하고 다음 순열을 확인해야 하므로
do-while
문을 사용한다.
#include <iostream>
#include <algorithm>
using namespace std;
int main() {
int n;
cin>>n;
int arr[n];
for(int i=1; i<=n; i++)
arr[i-1] = i;
do{
for(int i=0; i<n; i++)
cout<<arr[i]<<" ";
cout<<'\n';
} while(next_permutation(arr, arr + n));
return 0;
}
cf) 직접 next_permutation 구현하기
#include <algorithm> //sort 때문에 필요
bool next_permutation(int* a, int n){
//1. 무엇으로 시작하는 마지막 순열인지 찾기 (i 찾기)
int i = n-1;
while(i > 0 && a[i-1] >= a[i]) i--;
if(i <= 0) return false; //마지막 순열인 경우
//2. a[i-1]보다 크고 마지막 순열에 있는 수 중 가장 오른쪽에 있는 수 찾기 (j 찾기)
int j = n - 1;
while(j >= i && a[j] <= a[i-1]) j--;
//3.swap
swap(a[i-1], a[j]);
//4. 마지막 순열 오름차순
sort(a + i, a + n);
return true;
}
2. 순열로 브루트 포스 풀기
STL을 사용하니까 확실히 편하긴 편하다.. 재귀로 구현할 때는 직관적이지 않아서 구현하는데 시간이 오래 걸렸는데 순열을 사용하니까 빨리 풀린다!
[백준 10819 차이를 최대로] - Bruteforce
#include <iostream>
#include <algorithm>
using namespace std;
int main() {
int n;
cin>>n;
int arr[n];
for(int i=0; i<n; i++)
cin>>arr[i];
sort(arr, arr + n);
int ans = 0;
do{
int sum = 0;
for(int i=0; i<n-1; i++){
int sub = arr[i] - arr[i+1];
if(sub < 0) sub = -sub;
sum += sub;
}
ans = max(ans, sum);
} while(next_permutation(arr, arr + n));
cout<<ans<<'\n';
return 0;
}
[백준 10971 외판원 순회2] - Backtracking
- 123, 231, 312는 모두 같은 결과를 내는 것임을 알아내면 시간복잡도를 줄일 수 있다.
- 출발지를 하나로 고정시켜 반복을 피하는 것이다.
if(arr[0] != 0) break;
라는 조건을 걸면 된다.
#include <iostream>
#include <algorithm>
using namespace std;
int main() {
int n;
cin>>n;
int w[n][n];
for(int i=0; i<n; i++)
for(int j=0; j<n; j++)
cin>>w[i][j];
int arr[n]; //순서 저장
for(int i=0; i<n; i++)
arr[i] = i;
int ans = 10000000;
do {
if(arr[0] != 0) break; //시작점을 0로 고정한 경우 나머지는 볼 필요X
int cost = 0;
bool flag = true;
for(int i=0; i<n-1; i++){
if(w[arr[i]][arr[i+1]] == 0){ //길이 없는 경우
flag = false;
break;
}
cost += w[arr[i]][arr[i+1]];
}
//처음 도시로 돌아옴
int back = w[arr[n-1]][arr[0]];
if(!back) flag = false;
if(flag) ans = min(ans, cost + back);
} while(next_permutation(arr, arr + n));
cout<<ans<<'\n';
return 0;
}
반응형
'Algorithm > 코딩 테스트 준비 - 기초' 카테고리의 다른 글
[코딩 테스트 준비 - 기초] 8. 다이나믹 프로그래밍(DP) (0) | 2022.01.24 |
---|---|
[코딩 테스트 준비 - 기초] 7. 비트마스크(Bitmask) (0) | 2022.01.12 |
[코딩 테스트 준비 - 기초] 5. 브루트 포스 - 재귀 & 백트래킹 (0) | 2022.01.05 |
[코딩 테스트 준비 - 기초] 4. 브루트 포스 - N과 M & NM과 K (0) | 2021.12.31 |
[코딩 테스트 준비 - 기초] 3. 브루트 포스 - 그냥 다 해보기 (0) | 2021.12.23 |