본격적인 내용에 앞서, 앞으로 공부는 이렇게 진행할 예정입니다.
사이트 https://swexpertacademy.com/main/learn/course/courseList.do 를 접속하면 위처럼 무료로 수강할 수 있는 강좌 목록들이 나옵니다.
초심부터 한다는 생각으로 Programming Intermediate 과정부터 차근차근 해 볼 예정입니다.
Programming Intermediate 과정은 프로그래밍을 위한 기본 내용들을 학습할 수 있습니다.
Array부터 시작해 Tree까지, 알고리즘을 구현하는 데 있어서 가장 기본이 되는 자료 구조들을 학습해볼 수 있습니다. 그리고 Self Stdy Book 에서 이것들을 활용한 간단한 알고리즘 예제들도 풀어볼 수 있습니다.
혼자 알고리즘을 공부하는 데는 이만한 사이트가 정말 없는 것 같습니다.. 최고입니다.
Exhaustive Search(완전 검색)
완전 검색은 모든 경우의 수를 나열해보고 확인하는 기법입니다. Brute-Force 또는 Generate-And-Test 기법이라고 부르기도 합니다.
당연히 경우의 수가 상대적으로 작을 때 유용할 것이고, 수행 속도는 느릴 수 있지만 해답을 찾지 못할 확률은 적습니다.
그래서 문제를 풀 때는 우선 완전 검색으로 접근해 해답을 도출하고, 성능 개선을 위해 다른 알고리즘을 사용하고 해답을 확인하는 것이 바람직하다고 합니다.
문제에 대한 적합한 알고리즘이 바로 생각난다면 그것으로 하고, 생각이 안 나면 완전 검색부터 이용한다는 의미로 받아들였습니다.
| Baby-gin Game
0에서 9 사이의 숫자 카드에서 임의로 카드 6장을 뽑을 때, 3장의 카드가 연속적인 번호를 가지는 경우를 run 이라 하고, 3장의 카드가 동일한 번호를 갖는 경우를 triplete 라고 합니다. 6장의 카드가 run, triplete 로 구성되어 있을 경우를 Baby-gin 이라 합니다.
[예] 667767은 두 개의 triplete이다. => 666,777, Baby-gin
[예] 054060은 1 개의 run과 한 개의 triplete이다. => 000,456, Baby-gin
[예] 101123은 1 개의 triplete가 존재하나(111), 023이 run이 아니므로 Baby-gin 이 아니다.
이 문제를 완전 검색 방법으로 접근해 보는 방식은 다음과 같습니다.
- input으로 6개의 숫자를 입력받는다면 그것으로 만들 수 있는 모든 순열을 생각해 본다. 그런 다음 앞의 3자리와 뒤의 3자리를 잘라서 run과 triplete 여부를 테스트해 본다.
완전 검색 방식으로 코딩을 하는 것은 가장 단순하다고 볼 수 있습니다. 입력받은 6개의 숫자가 Baby-gin 인지 판별하는 코드를 순열로 경우의 수를 모두 판단하는 방식으로 작성해 봅니다.
[순열 알고리즘을 포함한 Baby-gin 판별 프로그램]
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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
#include <iostream>
#include <ctime>
using namespace std;
int num = 6;
int ginCount = 0; // count가 2이면 baby-gin이다.
int NumOfBabyGin = 0;
void swap(int* arr, int depth, int i) {
int temp = arr[depth];
arr[depth] = arr[i];
arr[i] = temp;
}
void print(int* arr, int r) {
for (int i = 0; i < r; i++) {
cout << arr[i] << ' ';
}
cout << endl;
}
void isBabyGin(int* arr, int n) {
// 1. 맨 앞의 3자리가 동일한 숫자일 경우 - triplete 1개
if (arr[0] == arr[1] && arr[1] == arr[2]) {
ginCount++;
}
// 2. 그 다음 3자리가 동일한 숫자일 경우 - triplete 1개
if (arr[3] == arr[4] && arr[4] == arr[5]) {
ginCount++;
}
// 3. 맨 앞의 3자리가 연속된 숫자일 경우 - run 1개
if (arr[0] + 1 == arr[1] && arr[1] + 1 == arr[2]) {
ginCount++;
}
// 4. 그 다음 3자리가 연속된 숫자일 경우 - run 1개
if (arr[3] + 1 == arr[4] && arr[4] + 1 == arr[5]) {
ginCount++;
}
if (ginCount == 2) {
NumOfBabyGin++;
}
ginCount = 0;
}
void permutation(int* arr, int depth, int n, int r) {
if (depth == r) {
//print(arr, r);
isBabyGin(arr, n);
return;
}
for (int i = depth; i < n; i++) {
swap(arr, depth, i);
permutation(arr, depth + 1, n, r);
swap(arr, depth, i);
}
}
int main() {
// 수 6개를 랜덤으로 지정하고자 할 때
/*
srand((unsigned int)time(0));
int arr[6];
int RandomNum;
for (int i = 0; i < num; i++) {
RandomNum = rand() % 10;
arr[i] = RandomNum;
}
*/
int arr[6] = { 1,3,2,7,7,7 };
// 순열 알고리즘으로 모든 경우의 수를 나타내고 baby-gin 판단하기
permutation(arr, 0, num, num);
cout << "뽑힌 6장의 카드 : ";
for (int i = 0; i < num; i++)
cout << arr[i] << ' ';
cout << endl;
if (NumOfBabyGin > 0) {
cout << "해당 6개의 숫자는 Baby-gin 입니다. ";
}
else {
cout << "해당 6개의 숫자는 Baby-gin이 아닙니다. ";
}
}
입력받은 6개의 숫자가 Baby-gin인지 아닌지를 판별해 줍니다.
6개의 숫자로 만들 수 있는 모든 6자리 숫자들을 순열 알고리즘을 통해 만든 다음, 그것을 Baby-gin인지 아닌지 판단하는 단순한 과정입니다.
이렇게 6개의 숫자에 대한 모든 경우의 수를 가지고 찾았기 때문에 이를 두고 완전검색이라고 할 수 있습니다.