반응형
문제 출처 :
https://www.acmicpc.net/problem/3665
알고리즘 분석 :
문제 해결에 필요한 사항
1. 위상 정렬(Topological Sort) :: http://www.crocus.co.kr/716
위상 정렬을 통해 해결 할 수 있는 문제이다.
이 문제에서 입력에서 오해하지 말아야 할 점은 예제를 통해 보면
4 1 2 3 4 3 1 2 3 4 2 3
에서
처음에 1 2 3 4 순위로 정해져있는 것 그 자체를 위상 정렬을 위해 추가시키고
그 후 1 2, 3 4, 2 3은 1->2 , 3->4 ,2->3이 아니고
1이 2보다 앞섰었다면 2->1로 바꾸고 2가 1보다 앞섰었다면 1->2로 바꾸는 것이다.
결국 1과 2의 순위를 스왑해라는 의미이다.
이렇게 위상 정렬 전, 간선의 상태, 들어오는 간선의 수만 잘 조절해주면
그 다음부터는 위상 정렬 알고리즘을 이용하여 해결해 줄 수 있다.
마지막에 큐가 0이면 사이클이 존재하는 것이고,
큐가 2이상이면 큐에서 사실 어느 것이 먼저 빠져도 위상 정렬이 되기에 정확한 순위를 알 수 없다.
소스 코드 :
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 150 151 152 153 154 155 156 | #include <iostream> #include <cstdio> #include <queue> #include <vector> #include <memory.h> #define swap(a,b){int t = a; a = b; b = t;} using namespace std; int arr[501]; int line[501]; int result[501]; int main() { int tCase; scanf("%d", &tCase); while (tCase--) { int n; scanf("%d", &n); vector<int> vc[501]; memset(arr, 0, sizeof(arr)); memset(line, 0, sizeof(line)); memset(result, 0, sizeof(result)); for (int i = 1; i <= n; i++) scanf("%d", &arr[i]); // 기존에 있는 등수를 위상 정렬에 이용한다. int prev, cur; for(int i = 1; i <= n - 1; i++) { prev = arr[i]; for (int j = i + 1; j <= n; j++) { cur = arr[j]; line[cur]++; vc[prev].push_back(cur); } } int m; scanf("%d", &m); for (int i = 1; i <= m; i++) { scanf("%d %d", &prev, &cur); // prev와 cur의 순위가 바뀌는데 // 어느것이 원래 앞에 있고 뒤에 있는지 모르니 // chk를 통해 확인해낸다. bool chk = false; for (int j = 0; j < vc[prev].size(); j++) { // 만약 prev가 앞에 있었다면 // cur이 이제는 순위가 더 앞선다는 의미 if (vc[prev][j] == cur) { // cur의 들어오는 간선을 지우고 prev의 간선을 늘린다. line[cur]--; line[prev]++; // cur에 prev를 추가하고, prev에 cur을 지운다. vc[cur].push_back(prev); vc[prev].erase(vc[prev].begin() + j); // 순위가 어디가 앞섰는지 알아냈으니 다음 for문은 못돌리게 한다. chk = true; break; } } if(chk == false) { for (int j = 0; j < vc[cur].size(); j++) { // 만약 cur이 앞에 있었다면 // prev가 이제는 순위가 더 앞선다는 의미 if (vc[cur][j] == prev) { // prev의 들어오는 간선을 지우고 cur의 간선을 늘린다. line[prev]--; line[cur]++; // prev에 cur를 추가하고, cur에 prev를 지운다. vc[prev].push_back(cur); vc[cur].erase(vc[cur].begin() + j); break; } } } } queue<int> q; // 들어오는 간선이 없는 노드를 먼저 큐에 추가 for (int i = 1; i <= n; i++) if (line[i] == 0) q.push(i); int flag = 0; for (int i = 0; i < n; i++) { // 큐가 비어있다면 사이클 if (q.empty()) { flag = 1; break; } // 큐가 2이상이라면 어느것이 먼저 뽑혀도 위상 정렬이 되기에 // 순서를 정확히 알 수 없다. else if (q.size() >= 2) { flag = 2; break; } int here = q.front(); q.pop(); result[i] = here; for (int j = 0; j < vc[here].size(); j++) { int there = vc[here][j]; if (--line[there] == 0) q.push(there); } } if (flag == 0) for (int i = 0; i < n; i++) printf("%d ", result[i]); else if (flag == 1) printf("IMPOSSIBLE"); else if (flag == 2) printf("?"); printf("\n"); } return 0; } // This source code Copyright belongs to Crocus // If you want to see more? click here >> | Crocus |
반응형
'Applied > 알고리즘 문제풀이' 카테고리의 다른 글
[1197번] 최소 스패닝 트리 (2) | 2017.04.03 |
---|---|
[2529번] 부등호 (0) | 2017.04.02 |
[1005번] ACM Craft (5) | 2017.04.02 |
[2637번] 장난감조립 (0) | 2017.04.01 |
[9470번] Strahler 순서 (0) | 2017.04.01 |