조합은 순서에 상관없이 n개의 원소 중 r개를 선택하는 경우의 수를 찾는 것
void Combination_recur(vector<int>& vec, vector<int>& selected, int start, int r)
{
if (r == 0) // 조합이 완성되었을 때 출력
{
PrintCombi(vec, selected);
return;
}
for (size_t i = start; i < vec.size(); i++)
{
selected[i] = 1;
Combination_recur(vec, selected, i + 1, r - 1); // ✅ r을 감소시킴
selected[i] = 0; // 백트래킹 (원상 복구)
}
}
Combination_recur(0, 2) // 시작점 0, r=2
├── 선택: {1} → Combination_recur(1, 1)
│ ├── 선택: {1, 2} → Combination_recur(2, 0) ✅ 출력: (1,2)
│ ├── 선택: {1, 3} → Combination_recur(3, 0) ✅ 출력: (1,3)
│ ├── 선택: {1, 4} → Combination_recur(4, 0) ✅ 출력: (1,4)
│
├── 선택: {2} → Combination_recur(2, 1)
│ ├── 선택: {2, 3} → Combination_recur(3, 0) ✅ 출력: (2,3)
│ ├── 선택: {2, 4} → Combination_recur(4, 0) ✅ 출력: (2,4)
│
├── 선택: {3} → Combination_recur(3, 1)
│ ├── 선택: {3, 4} → Combination_recur(4, 0) ✅ 출력: (3,4)
📌 조합의 특징:
순열은 순서를 고려하여 n개의 원소 중 r개를 선택하는 경우의 수를 찾는 것
void Permutation_recur(vector<int>& vec, int depth, int n)
{
if (depth == n)
{
PrintVector(vec);
return;
}
for (int i = depth; i < n; i++)
{
swap(vec[depth], vec[i]); // ✅ 순서를 변경
Permutation_recur(vec, depth + 1, n);
swap(vec[depth], vec[i]); // ✅ 백트래킹 (원래대로 복구)
}
}
💡 핵심 개념:
#include <iostream>
#include <vector>
using namespace std;
void PrintVector(const vector<int>& vec)
{
for (int num : vec)
{
cout << num << " ";
}
cout << endl;
}
void Permutation_recur(vector<int>& vec, int depth, int n)
{
if (depth == n) // ✅ depth가 n이 되면 출력
{
PrintVector(vec);
return;
}
for (int i = depth; i < n; i++)
{
swap(vec[depth], vec[i]); // ✅ 현재 위치(depth)와 i를 교환
Permutation_recur(vec, depth + 1, n); // ✅ 다음 단계 진행
swap(vec[depth], vec[i]); // ✅ 백트래킹 (원상 복구)
}
}
int main()
{
vector<int> arr = {1, 2, 3};
Permutation_recur(arr, 0, arr.size());
return 0;
}
vec = [1, 2, 3]
swap(0,0) → [1, 2, 3]
Permutation_recur(1, 3) 호출
swap(1,1) → [1, 2, 3]
Permutation_recur(2, 3) 호출
swap(2,2) → [1, 2, 3]
Permutation_recur(3, 3) 호출
✅ depth == n이므로 출력
출력: 1 2 3
🚀 순열 하나 완성!
swap(1,2) → [1, 3, 2]
Permutation_recur(2, 3) 호출
swap(2,2) → [1, 3, 2]
Permutation_recur(3, 3) 호출
✅ depth == n이므로 출력
출력: 1 3 2
Permutation_recur(0, 3) // depth=0
├── swap(0,0): [1,2,3] → Permutation_recur(1, 3)
│ ├── swap(1,1): [1,2,3] → Permutation_recur(2, 3)
│ │ ├── swap(2,2): [1,2,3] ✅ 출력 (1,2,3)
│ │ ├── (백트래킹)
│ ├── swap(1,2): [1,3,2] → Permutation_recur(2, 3)
│ │ ├── swap(2,2): [1,3,2] ✅ 출력 (1,3,2)
│ │ ├── (백트래킹)
│ ├── (백트래킹)
│
├── swap(0,1): [2,1,3] → Permutation_recur(1, 3)
│ ├── swap(1,1): [2,1,3] → Permutation_recur(2, 3)
│ │ ├── swap(2,2): [2,1,3] ✅ 출력 (2,1,3)
│ │ ├── (백트래킹)
│ ├── swap(1,2): [2,3,1] → Permutation_recur(2, 3)
│ │ ├── swap(2,2): [2,3,1] ✅ 출력 (2,3,1)
│ │ ├── (백트래킹)
│ ├── (백트래킹)
│
├── swap(0,2): [3,2,1] → Permutation_recur(1, 3)
│ ├── swap(1,1): [3,2,1] → Permutation_recur(2, 3)
│ │ ├── swap(2,2): [3,2,1] ✅ 출력 (3,2,1)
│ │ ├── (백트래킹)
│ ├── swap(1,2): [3,1,2] → Permutation_recur(2, 3)
│ │ ├── swap(2,2): [3,1,2] ✅ 출력 (3,1,2)
│ │ ├── (백트래킹)
│ ├── (백트래킹)
👉 결국 swap을 이용해 "현재 자리(depth)에 올 수 있는 모든 값"을 넣으면서 순열을 찾는 것!
👉 이제 swap(0,0), swap(1,1), swap(2,2)가 왜 필요한지 이해되셨나요? 😃
혹시 추가로 이해가 안 되는 부분 있으면 더 설명해드릴게요! 🚀
개념 조합(Combination) 순열(Permutation)
순서 | ❌ 무관 (ex: {1,2} == {2,1}) | ✅ 중요 (ex: {1,2} ≠ {2,1}) |
방법 | r-1을 감소시키며 선택 | swap을 활용하여 순서 바꿈 |
중복 여부 | 중복 없이 선택 | 중복 허용 |
백트래킹 | 선택 후 해제 | swap() 후 원상 복구 |
배열 출력하는 방법🚀 (0) | 2025.03.01 |
---|---|
📌 비트 시프트 연산 (Bit Shift Operation) (0) | 2025.02.21 |
트리 vs 그래프 (0) | 2025.01.23 |
이분 탐색 //(Binary Search) (0) | 2025.01.22 |
그리디 알고리즘 (Greedy Algorithm) (0) | 2025.01.21 |