Problem Solving/알고리즘
순열, 조합 알고리즘 - DFS로 구하기(백트래킹), C++, Python
돌돌김
2020. 2. 25. 21:18
순열, 조합은 정말정말 많이 나오는데 cpp의 stl 라이브러리 중 next_permutation으로 구할 수 있다.
하지만 next_permutation은 N이 20만 넘어가도 터질 위험에 처한다.. 시간복잡도가 크기 때문이다. N이 10 언저리일때 쓰면 좋다.
재귀를 사용하여 DFS탐색을 통해 순열, 조합을 구하는 것이 가장 안전하고 깔끔하다.
순열 구하기
#include<iostream>
#include<string.h>
#include<vector>
#define MAX 5
using namespace std;
vector<int>arr;
vector<int>result;
int visit[MAX];
/* 순열 구하기 */
void prt_permu() {
for (int i = 0; i < result.size(); i++) {
cout << result[i] << ' ';
}
cout << endl;
}
void dfs_permu(int cnt){
if (cnt == 3) { // 찾으려는 개수
prt_permu();
return;
}
for (int i = 0; i < MAX; i++) {
if (visit[i] == true) continue;
visit[i] = true;
result.push_back(arr[i]);
dfs_permu(cnt + 1);
result.pop_back();
visit[i] = false;
}
}
int main() {
for (int i = 0; i <MAX; i++) {
arr.push_back(i+1);
}
dfs_permu(0);
}
/*
1 2 3
1 2 4
1 2 5
1 3 2
1 3 4
1 3 5
1 4 2
1 4 3
1 4 5
1 5 2
1 5 3
1 5 4
2 1 3
2 1 4
2 1 5
2 3 1
2 3 4
2 3 5
.
.
.
*/
조합 구하기
#include<iostream>
#include<string.h>
#include<vector>
#define MAX 5
using namespace std;
vector<int>arr;
vector<int>result;
int visit[MAX];
/* 조합 구하기 */
void prt_combi() {
for (int i = 0; i < MAX; i++) {
if (visit[i] == true) {
cout << arr[i] << ' ';
}
}
cout << endl;
}
void dfs_combi(int idx, int cnt) {
if (cnt == 3) {
prt_combi();
return;
}
for (int i = idx; i < MAX; i++) {
if (visit[i] == true) continue;
visit[i] = true;
dfs_combi(i, cnt + 1);
visit[i] = false;
}
}
int main() {
for (int i = 0; i <MAX; i++) {
arr.push_back(i+1);
}
dfs_combi(0, 0);
/*
1 2 3
1 2 4
1 2 5
1 3 4
1 3 5
1 4 5
2 3 4
2 3 5
2 4 5
3 4 5
*/
}
Python으로 구한다면 아래와 같다.
순열
itertools
from itertools import permutations, combinations data = ['a', 'b', 'c'] result = list(permutations(data, 3)) print(result) #[('a', 'b', 'c'), ('a', 'c', 'b'), ('b', 'a', 'c'), ('b', 'c', 'a'), ('c', 'a', 'b'), ('c', 'b', 'a')]
backtracking
def dfs(level): if level == r: # r개를 뽑은 경우 print(result) return for i in range(len(n)): if checked[i] == True: continue result[level] = n[i] checked[i] = True dfs(level+1) checked[i] = False n = [i+1 for i in range(3)] r = 2 # r개 뽑기 result = [0] * r checked = [False] * len(n) dfs(0) # [1, 2] # [1, 3] # [2, 1] # [2, 3] # [3, 1] # [3, 2]
조합
itertools
from itertools import permutations, combinations data = ['a', 'b', 'c'] result = list(combinations(data, 2)) # 조합 print(result) #[('a', 'b'), ('a', 'c'), ('b', 'c')]
backtracking
def dfs(level, BeginWith): if level == r: # r개를 뽑은 경우 print(result) return for i in range(BeginWith, len(n)): result[level] = n[i] dfs(level+1, i+1) n = [i for i in range(10)] r = 6 # r개 뽑기 result = [0] * r dfs(0, 0) # [1, 2, 3] # [1, 2, 4] # [1, 2, 5] # [1, 3, 4] # [1, 3, 5] # [1, 4, 5] # [2, 3, 4] # [2, 3, 5] # [2, 4, 5] # [3, 4, 5]
중복순열
itertools
from itertools import product n = [i+1 for i in range(3)] r = 2 result = list(product(n, repeat=r)) print(result) # [ # (1, 1), (1, 2), (1, 3), # (2, 1), (2, 2), (2, 3), # (3, 1), (3, 2), (3, 3) # ]
backtracking
def dfs(count): if count == m: print(*result) return for i in range(1,n+1): result.append(i) dfs(count+1) result.pop() dfs(0)
중복조합
itertools
from itertools import combinations_with_replacement n = [i+1 for i in range(3)] r = 2 result = list(combinations_with_replacement(n, r)) # 중복조합에서는 repeat가 안들어간다. print(result) # [ # (1, 1), (1, 2), (1, 3), # (2, 2), (2, 3), # (3, 3) # ]
backtracking
result = [] def dfs(idx, count): if count == m: print(*result) return for i in range(idx, n): result.append(i+1) dfs(i, count+1) result.pop() dfs(0, 0)