백트래킹을 이용하여 다양한 문제를 구현해보자.
모든 문제는 백준 문제를 이용하여 문제를 적용하고 풀어보려 한다.
1. 순열(nPr)
N과 M(1) :: https://www.acmicpc.net/problem/15649
순열은 아래와 같이 코딩 할 수 있다.
현재 값을 넣고 방문을 표시해준 후 다음 재귀를 반복하면 방문된 값들 빼고 계속 처리를 할 수 있다.
그 후 내가 출력 할 값이 m과 같아지면 출력을 하면 된다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45  | #include <iostream> #include <cstdio> #include <vector> using namespace std; int n, m; vector<int> vc; // 내가 출력할 것 bool visit[10]; // 그 숫자가 쓰는지확인 void dfs() {     if (vc.size() == m)     {         for (auto i : vc)             printf("%d ", i);         printf("\n");         return;     }     for (int i = 1; i <= n; i++)     {         if (!visit[i])         {             visit[i] = true;             vc.push_back(i);             dfs();             vc.pop_back();             visit[i] = false;         }     } } int main() {     scanf("%d %d", &n, &m);     dfs();     return 0; } //                                                       This source code Copyright belongs to Crocus //                                                        If you want to see more? click here >>  | Crocus | 
N과 M(5) :: https://www.acmicpc.net/problem/15654
인덱스 내로 해결 할 수 없는 값들을 처리하는 방법이다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51  | #include <iostream> #include <cstdio> #include <vector> #include <algorithm> #include <unordered_map> using namespace std; int n, m; int arr[10]; unordered_map<int, int> visit; vector<int> vc; void dfs(int cnt) {     if (vc.size() == m)     {         for (auto i : vc)             printf("%d ", i);         printf("\n");         return;     }     for (int i = 0; i < n; i++)     {         if (vc.size() < m)         {             if (!visit[arr[i]])             {                 vc.push_back(arr[i]);                 visit[arr[i]] = 1;                 dfs(i + 1);                 visit[arr[i]] = 0;                 vc.pop_back();             }         }     } } int main() {     scanf("%d %d", &n, &m);     for (int i = 0; i < n; i++)         scanf("%d", &arr[i]);     sort(arr, arr + n);     dfs(0);     return 0; } //                                                       This source code Copyright belongs to Crocus //                                                        If you want to see more? click here >>  | Crocus | 
N과 M(9) :: https://www.acmicpc.net/problem/15663
중복된 순열 값을 어떻게 처리할 지 생각해보자.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66  | #include <iostream> #include <cstdio> #include <vector> #include <algorithm> #include <map> #include <unordered_map> using namespace std; typedef pair<int, int> pii; int n, m; pii arr[10]; map<pii, int> visit; map<vector<int>, int> mp; vector<int> vc; void dfs(int cnt) {     if (vc.size() == m && !mp.count(vc))     {         mp[vc] = 1;         return;     }     for (int i = 0; i < n; i++)     {         if (vc.size() < m)         {             if(!visit[arr[i]])             {                 vc.push_back(arr[i].first);                 visit[arr[i]] = true;                 dfs(i + 1);                 visit[arr[i]] = false;                 vc.pop_back();              }         }     } } int main() {     scanf("%d %d", &n, &m);     for (int i = 0; i < n; i++)     {         int val;         scanf("%d", &val);         arr[i] = { val, i };     }     sort(arr, arr + n);     dfs(0);     for (auto it = mp.begin(); it != mp.end(); it++)     {         for (auto i : it->first)             printf("%d ", i);         printf("\n");     }     return 0; } //                                                       This source code Copyright belongs to Crocus //                                                        If you want to see more? click here >>  | Crocus | 
2. 조합(nCr)
N과 M(2) :: https://www.acmicpc.net/problem/15650
조합은 이전 수의 참조를 하면 안된다는 것을 생각하면 쉽게 구현 할 수 있다.
재귀에 인자가 들어가는데 현재 인덱스 다음 인덱스를 인자로 보내어 이전 값을 참조 못하도록 하자.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39  | #include <iostream> #include <cstdio> #include <vector> using namespace std; int n, m; vector<int> vc; void dfs(int cnt) {     if (vc.size() == m)     {         for (auto i : vc)             printf("%d ", i);         printf("\n");         return;     }     for (int i = cnt; i <= n; i++)     {         if (vc.size() < m)         {             vc.push_back(i);             dfs(i + 1);             vc.pop_back();         }     } } int main() {     scanf("%d %d", &n, &m);     dfs(1);     return 0; } //                                                       This source code Copyright belongs to Crocus //                                                        If you want to see more? click here >>  | Crocus | 
N과 M(6) :: https://www.acmicpc.net/problem/15655
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44  | #include <iostream> #include <cstdio> #include <vector> #include <algorithm> using namespace std; int n, m; int arr[10]; vector<int> vc; void dfs(int cnt) {     if (vc.size() == m)     {         for (auto i : vc)             printf("%d ", i);         printf("\n");         return;     }     for (int i = cnt; i < n; i++)     {         if (vc.size() < m)         {             vc.push_back(arr[i]);             dfs(i + 1);             vc.pop_back();         }     } } int main() {     scanf("%d %d", &n, &m);     for (int i = 0; i < n; i++)         scanf("%d", &arr[i]);     sort(arr, arr + n);     dfs(0);     return 0; } //                                                       This source code Copyright belongs to Crocus //                                                        If you want to see more? click here >>  | Crocus | 
N과 M(10) :: https://www.acmicpc.net/problem/15664
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66  | #include <iostream> #include <cstdio> #include <vector> #include <algorithm> #include <map> #include <unordered_map> using namespace std; typedef pair<int, int> pii; int n, m; pii arr[10]; map<pii, int> visit; map<vector<int>, int> mp; vector<int> vc; void dfs(int cnt) {     if (vc.size() == m && !mp.count(vc))     {         mp[vc] = 1;         return;     }     for (int i = cnt; i < n; i++)     {         if (vc.size() < m)         {             if(!visit[arr[i]])             {                 vc.push_back(arr[i].first);                 visit[arr[i]] = true;                 dfs(i + 1);                 visit[arr[i]] = false;                 vc.pop_back();              }         }     } } int main() {     scanf("%d %d", &n, &m);     for (int i = 0; i < n; i++)     {         int val;         scanf("%d", &val);         arr[i] = { val, i };     }     sort(arr, arr + n);     dfs(0);     for (auto it = mp.begin(); it != mp.end(); it++)     {         for (auto i : it->first)             printf("%d ", i);         printf("\n");     }     return 0; } //                                                       This source code Copyright belongs to Crocus //                                                        If you want to see more? click here >>  | Crocus | 
3. 중복 순열(nπr)
N과 M(3) :: https://www.acmicpc.net/problem/15651
중복 순열은 중복해서 뽑아도 되고 이전 값을 뽑아도 된다는 것을 이용하여 코딩해보자.
위의 내용들을 이해하기 시작했다면 이 코드도 충분히 이해 할 수 있다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39  | #include <iostream> #include <cstdio> #include <vector> using namespace std; int n, m; vector<int> vc; void dfs() {     if (vc.size() == m)     {         for (auto i : vc)             printf("%d ", i);         printf("\n");         return;     }     for (int i = 1; i <= n; i++)     {         if (vc.size() < m)         {             vc.push_back(i);             dfs();             vc.pop_back();         }     } } int main() {     scanf("%d %d", &n, &m);     dfs();     return 0; } //                                                       This source code Copyright belongs to Crocus //                                                        If you want to see more? click here >>  | Crocus | 
N과 M(7) :: https://www.acmicpc.net/problem/15656
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44  | #include <iostream> #include <cstdio> #include <vector> #include <algorithm> using namespace std; int n, m; int arr[10]; vector<int> vc; void dfs(int cnt) {     if (vc.size() == m)     {         for (auto i : vc)             printf("%d ", i);         printf("\n");         return;     }     for (int i = 0; i < n; i++)     {         if (vc.size() < m)         {             vc.push_back(arr[i]);             dfs(i + 1);             vc.pop_back();         }     } } int main() {     scanf("%d %d", &n, &m);     for (int i = 0; i < n; i++)         scanf("%d", &arr[i]);     sort(arr, arr + n);     dfs(0);     return 0; } //                                                       This source code Copyright belongs to Crocus //                                                        If you want to see more? click here >>  | Crocus | 
N과 M(10) :: https://www.acmicpc.net/problem/15664
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60  | #include <iostream> #include <cstdio> #include <vector> #include <algorithm> #include <map> #include <unordered_map> using namespace std; typedef pair<int, int> pii; int n, m; pii arr[10]; vector<int> vc; map<vector<int>, int> mp; void dfs(int cnt) {     if (vc.size() == m && !mp.count(vc))     {         mp[vc] = 1;         return;     }     for (int i = 0; i < n; i++)     {         if (vc.size() < m)         {             vc.push_back(arr[i].first);             dfs(i + 1);             vc.pop_back();          }     } } int main() {     scanf("%d %d", &n, &m);     for (int i = 0; i < n; i++)     {         int val;         scanf("%d", &val);         arr[i] = { val, i };     }     sort(arr, arr + n);     dfs(0);     for (auto it = mp.begin(); it != mp.end(); it++)     {         for (auto i : it->first)             printf("%d ", i);         printf("\n");     }     return 0; } //                                                       This source code Copyright belongs to Crocus //                                                        If you want to see more? click here >>  | Crocus | 
4. 중복 조합(nHr)
N과 M(4) :: https://www.acmicpc.net/problem/15652
중복 조합은 중복 순열에서 이전 값들을 다시 쓸 수 없게만 처리해주면 된다.
이때 중복해서 계속 뽑을 수 있으니 조건에서 간단한 예외처리를 생각해줘보자.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39  | #include <iostream> #include <cstdio> #include <vector> using namespace std; int n, m; vector<int> vc; void dfs(int cnt) {     if (vc.size() == m)     {         for (auto i : vc)             printf("%d ", i);         printf("\n");         return;     }     for (int i = 1; i <= n; i++)     {         if (vc.size() < m && (vc.size() == 0 || vc[vc.size() - 1] <= i))         {             vc.push_back(i);             dfs(i + 1);             vc.pop_back();         }     } } int main() {     scanf("%d %d", &n, &m);     dfs(1);     return 0; } //                                                       This source code Copyright belongs to Crocus //                                                        If you want to see more? click here >>  | Crocus | 
N과 M(8) :: https://www.acmicpc.net/problem/15657
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44  | #include <iostream> #include <cstdio> #include <vector> #include <algorithm> using namespace std; int n, m; int arr[10]; vector<int> vc; void dfs(int cnt) {     if (vc.size() == m)     {         for (auto i : vc)             printf("%d ", i);         printf("\n");         return;     }     for (int i = 0; i < n; i++)     {         if (vc.size() < m && (!vc.size() || vc[vc.size() - 1] <= arr[i]))         {             vc.push_back(arr[i]);             dfs(i + 1);             vc.pop_back();         }     } } int main() {     scanf("%d %d", &n, &m);     for (int i = 0; i < n; i++)         scanf("%d", &arr[i]);     sort(arr, arr + n);     dfs(0);     return 0; } //                                                       This source code Copyright belongs to Crocus //                                                        If you want to see more? click here >>  | cs | 
N과 M(12) :: https://www.acmicpc.net/problem/15666
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60  | #include <iostream> #include <cstdio> #include <vector> #include <algorithm> #include <map> #include <unordered_map> using namespace std; typedef pair<int, int> pii; int n, m; pii arr[10]; vector<int> vc; map<vector<int>, int> mp; void dfs(int cnt) {     if (vc.size() == m && !mp.count(vc))     {         mp[vc] = 1;         return;     }     for (int i = 0; i < n; i++)     {         if (vc.size() < m && (!vc.size() || vc[vc.size() - 1] <= arr[i].first))         {             vc.push_back(arr[i].first);             dfs(i + 1);             vc.pop_back();          }     } } int main() {     scanf("%d %d", &n, &m);     for (int i = 0; i < n; i++)     {         int val;         scanf("%d", &val);         arr[i] = { val, i };     }     sort(arr, arr + n);     dfs(0);     for (auto it = mp.begin(); it != mp.end(); it++)     {         for (auto i : it->first)             printf("%d ", i);         printf("\n");     }     return 0; } //                                                       This source code Copyright belongs to Crocus //                                                        If you want to see more? click here >>  | Crocus | 
TIP
조합을 다른 방식으로 한번 이해해보자.
우리는 고등학생 때 조합의 방식을 아래와 같이 생각해본 적이있다.
7개중 4개를 뽑으려면 ㅁ ㅁ ㅁ ㅁ ㅁ ㅁ ㅁ을 두고 이중에 4군데에만 1을 넣으면 된다고 생각 할 수 있다.
이걸 코드화 시키면 아래와 같다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28  | #include <cstdio> #include <iostream> #include <vector> #include <algorithm> using namespace std; int main() {     vector<int> vc = { 0,0,0,1,1,1,1 };     for (int i = 0; i < vc.size(); i++)         if (vc[i])             cout << i << " ";     cout << endl;     while (next_permutation(vc.begin(), vc.end())) {         for (int i = 0; i < vc.size(); i++)             if (vc[i])                 cout << i << " ";         cout << endl;     } } //                                                       This source code Copyright belongs to Crocus //                                                        If you want to see more? click here >>  | Crocus | 
'Applied > 알고리즘' 카테고리의 다른 글
| 편집거리 알고리즘 (2) | 2018.06.29 | 
|---|---|
| 컨벡스 헐 알고리즘(Convex Hull Algorithm) (3) | 2018.06.21 | 
| 확장 유클리드 알고리즘 (2) | 2018.04.18 | 
| 모듈러 연산(Modular Arithmetic) (8) | 2018.04.18 | 
| 과반수 찾기 알고리즘 (4) | 2018.04.08 |