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 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 | #include <iostream> #include <cstdio> #include <fstream> #include <time.h> using namespace std; int** adjacent_arr; char line[64]; int node_size; int* case_list; int color_set[3] = { 1,2,3 }; void initArray(); void Swap(int& case_list1, int& case_list2); void Permutation(int depth); int testNode(int node); int searchNodeColor(int node); void showVertexColor(); int main(void) { initArray(); Permutation(0); //성공하면exit()로 나가므로,여기까지오면실패 abort(); return 0; } void initArray() { ifstream ifs("./input/graph15_yes.dat", ios::binary); if (ifs.is_open() == false) cout << "File Open Failed" << endl; ifs.getline(line, 64); node_size = atoi(line); case_list = new int[node_size]; for (int i = 0; i < node_size; i++) case_list[i] = i; adjacent_arr = new int*[node_size]; for (int i = 0; i < node_size; i++) adjacent_arr[i] = new int[node_size]; for (int i = 0; i < node_size; i++) for (int j = 0; j < node_size; j++) adjacent_arr[i][j] = -1; while (ifs.getline(line, 64)) { char* pch = strtok(line, "<"); int node = atoi(pch) - 1; while (true) { pch = strtok(NULL, "> "); if (pch == nullptr) break; int adjacent_node = atoi(pch) - 1; adjacent_arr[node][adjacent_node] = 1; adjacent_arr[adjacent_node][node] = 1; } } } void Swap(int& case_list1, int& case_list2) { int temp = case_list1; case_list1 = case_list2; case_list2 = temp; } // 탐색할 수 있는 모든 경우의 수를 구합니다 // node_size가 5라면, {0,1,2,3,4}의 Permutation이 됩니다. // 구한 경우의 수 마다 색을 지닐 수 있는지 검사합니다. void Permutation(int depth) { int result = 0; if (depth == node_size) { for (int i = 0; i < node_size; i++) { result += searchNodeColor(i); if (result < 0) return; } if (result >-1) { showVertexColor(); exit(0); } cout << endl; cout << endl; return; } else { for (int i = 0; i < 3; i++) { Swap(color_set[i], color_set[2]); case_list[depth] = color_set[2]; Permutation(depth +1); Swap(color_set[i], color_set[2]); } } } //주어진 노드를 보고 주위에 색이 꽉 찼는지 검사합니다. int searchNodeColor(int node) { int rgb[3] = { 1,2,3 }; int myColor = case_list[node]; for (int i = 0; i < node_size; i++) { if (adjacent_arr[node][i] == 1) { if (myColor == case_list[i]) return -1; } } return 0; } void showVertexColor() { for (int i = 0; i < node_size; i++) { cout << "V" << i << " : "; switch (case_list[i]) { case 1: cout << "R"; break; case 2: cout << "G"; break; case 3: cout << "B"; break; } cout << endl; } } | cs |
처음에 풀었던 것은
만약 node수가 5개라면
{0,1,2,3,4}의 5!의 경우의 수를 가지고 색을 하나씩 채워갔는데요.
색을 하나 채우고 다른 노드들과 색의 관계가 어떤지 검사하고
ok면 다음 노드로
fail면 처음 부터 시작했읍니다.
하나라도 성공하면 성공이고,
실패를 알려면 모든 경우의 수에 테스트를 해야했습니다.
이것은 node수가 15개라면 15!이라는 어마어마한 케이스를 다 보므로 상당히 느렸읍니다.
그 다음은 힌트를 가지고 풀었는데요
만약 node수가 5개라면
RRRRR
~~~~
RGBRG
~~~~
BBBBB
이런식으로 이미 색을 칠한 노드들을 구할 수 있어요.
이 색이 칠해진 노드들이 규칙에 맞나 검사를하면 3^n으로 가능합니다.
제가 살펴본 규칙은 노드의 색깔과 겹치는 색깔이 주위 노드에 있다면 fail로 처리했읍니다.
처음에 풀었던 것은 순열을 이용했구요 위에 것은 중복 순열을 이용하여 {r,g,b}이 세 경우에서 n개를 뽑는 것을 사용하였읍니다.
이 경우도 역시
하나라도 성공하면 성공이고,
실패를 알려면 모든 경우의 수에 테스트를 해야했습니다.
하지만 node수에 따라 3^n이 되어 위에 것보다 훨씬 빠릅니다.
휴휴
수고하셨읍니다돌려보고감상평올리겠읍니다
http://gall.dcinside.com/board/view/?id=programming&no=582184&page=1