반응형
문제 출처 :
https://www.acmicpc.net/problem/3977
알고리즘 분석 :
문제 해결에 필요한 사항
1. SCC :: http://www.crocus.co.kr/950
이 문제는 SCC를 이용하여 풀 수 있다.
축구 전술을 하는데 진입차수 Indegree가 0인것이 딱 하나 있어야 그 정점을 시작으로하면 모든 그래프를 순회 가능하기 때문이다.
2번 테스트케이스를 보면
4 4 0 3 1 0 2 0 2 3
진입차수가 0인것이 1,2 두개가 있기에 어느점에서 시작해도 모든 그래프를 순회 할 수 없다. 따라서 Confused이다.
1번 예제의 경우
4 4 0 1 1 2 2 0 2 3
진입차수가 0인것이 0-1-2로 구성된 SCC이기에 0,1,2 3개가 답이 될 수 있는 것이다.
소스 코드 :
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 | #include <iostream> #include <cstdio> #include <algorithm> #include <stack> #include <vector> #include <memory.h> using namespace std; const int MAX = 101000; vector<vector<int>> adj; stack<int> s; bool finish[MAX]; // SCC 분리가 완료된 정점 = true int dfsn[MAX]; // 각 노드 dfs 번호 int SCCnum[MAX]; // SCC의 인덱스 번호 int indegree[MAX]; int cnt; // dfs 번호 int SCCtotal; // SCC 총 개수 int dfs(int cur) { dfsn[cur] = ++cnt; s.push(cur); int result = dfsn[cur]; int len = adj[cur].size(); for (int i = 0; i < len; i++) { int next = adj[cur][i]; if (!dfsn[next]) result = min(result, dfs(next)); else if (!finish[next]) result = min(result, dfsn[next]); } if (result == dfsn[cur]) { while (1) { int t = s.top(); s.pop(); finish[t] = true; SCCnum[t] = SCCtotal; if (t == cur) break; } SCCtotal++; } return result; } int main() { int tc; scanf("%d", &tc); while (tc--) { int V, E; scanf("%d %d", &V, &E); memset(finish, false, sizeof(finish)); memset(dfsn, 0, sizeof(dfsn)); memset(SCCnum, 0, sizeof(SCCnum)); memset(indegree, 0, sizeof(indegree)); adj.clear(); adj.resize(V + 1); cnt = 0; SCCtotal = 0; for (int i = 0; i < E; i++) { int from, to; scanf("%d %d", &from, &to); adj[from].push_back(to); } for (int i = 0; i < V; i++) if (!dfsn[i]) dfs(i); // 진입 차수를 구한다. for (int i = 0; i < V; i++) for (int j : adj[i]) if (SCCnum[i] != SCCnum[j]) indegree[SCCnum[j]]++; // 진입 차수가 0인 부분 즉, 시작 부분이 있다면 target과 cntdegree를 계산 int cntdegree = 0; int target = 0; for (int i = 0; i < SCCtotal; i++) if (indegree[i] == 0) target = i, cntdegree++; // 진입 차수가 2개 이상이면 Confused if (cntdegree > 1) printf("Confused\n"); // 진입차수가 1일 때 그 SCC 넘버랑 같은 정점을 모두 출력 else for (int i = 0; i < V; i++) if (SCCnum[i] == target) printf("%d\n", i); printf("\n"); } return 0; } // This source code Copyright belongs to Crocus // If you want to see more? click here >> | Crocus |
반응형
'Applied > 알고리즘 문제풀이' 카테고리의 다른 글
[4198번] 열차정렬 (0) | 2017.07.25 |
---|---|
[2999번] 비밀 이메일 (0) | 2017.07.22 |
[4196번] 도미노 (0) | 2017.07.22 |
[6543번] The Bottom of a Graph (0) | 2017.07.22 |
[2150번] Strongly Connected Component (0) | 2017.07.21 |