Boj 13344) Chess Tournament
문제
방법 1
설명
등호가 붙은 번호끼리 먼저 분리집합을 수행한다. 그리고 미리 저장해놓은 <
, >
에 대한 관계를 분리집합의 대표 번호로 환원해서 그래프의 인접 리스트를 만든다. 그리고 DFS 로 Directed Graph 의 Cycle 을 찾아내면 된다.
시간 복잡도
O(\(\mathrm{N} + \mathrm{M}\))
코드
const int MAX_IN = 50001;
int rootTB[MAX_IN];
void Init(int n)
{
for (int i = 0; i <= n; i++) rootTB[i] = i;
}
int Find(int a)
{
if (rootTB[a] == a) return a;
return rootTB[a] = Find(rootTB[a]);
}
void Union(int from, int to)
{
from = Find(from);
to = Find(to);
if (from == to) return;
rootTB[from] = to;
}
vector<pair<int,int>> relates;
vector<int> lines[MAX_IN];
bool res = true;
bool stTB[MAX_IN], edTB[MAX_IN];
void DFS(int cur)
{
cur = Find(cur);
stTB[cur] = true;
for (int l : lines[cur])
{
if (!stTB[l]) DFS(l);
else if (!edTB[l]) res = false;
}
edTB[cur] = true;
}
int main()
{
int n, m;
cin >> n >> m;
Init(n);
for (int i = 0; i < m; i++)
{
int a, b; char c;
cin >> a >> c >> b;
if (c == '=') Union(a, b);
else {
if (c == '<') swap(a, b);
relates.push_back({ a,b });
}
}
for (auto& r : relates) lines[Find(r.first)].push_back(Find(r.second));
for (int i = 0; i < n; i++) { if (!res) break; if (!stTB[Find(i)]) DFS(i); }
cout << (res ? "consistent" : "inconsistent");
}
방법 2 (삽질)
설명
맨 처음에 시도했던 방법으로, 위상정렬을 사용하였다. AC 는 나왔지만 3초가 나와서 벙쪘었는데. 나중에 생각해보니 아래의 주석처리한 reserve()
함수가 문제였다. 왜냐하면 최악의 경우 reserve()
함수만 거의 m
번 사용할 수도 있기 때문이다. vector
의 삽입 함수는 amortized O(n) 이라는 걸 생각해보면 매우 멍청한 짓이었다. 그래서 메모해둔다.
시간 복잡도
O(\(\mathrm{N} + \mathrm{M}\))
코드
const int MAX_IN = 50001;
int n_targets[MAX_IN];
vector<int> srcs[MAX_IN];
int rootTB[MAX_IN], sizeTB[MAX_IN];
void Init(int n)
{
for (int i = 0; i <= n; i++) rootTB[i] = i;
}
int Find(int a)
{
if (rootTB[a] == a) return a;
return rootTB[a] = Find(rootTB[a]);
}
bool Union(int from, int to)
{
from = Find(from);
to = Find(to);
if (from == to) return false;
rootTB[from] = to;
return true;
}
int main()
{
fastio;
int n, m;
cin >> n >> m;
Init(n);
for (int i = 0; i < m; i++)
{
int a, b; char c;
cin >> a >> c >> b;
if (c == '=') {
Union(a, b);
continue;
}
if (c == '<') swap(a, b);
srcs[a].push_back(b);
n_targets[b]++;
}
for (int i = 0; i < n; i++)
{
int dest = Find(i);
if (dest != i)
{
// srcs[dest].reserve(srcs[dest].size() + srcs[i].size());
for(int s : srcs[i]) srcs[dest].push_back(s);
//srcs[i].clear();
n_targets[dest] += n_targets[i];
n_targets[i] = -1;
}
}
queue<int> q;
for (int i = 0; i < n; i++)
if (n_targets[i] == 0) q.push(i);
bool inconsist = false;
while (!q.empty())
{
int cur = q.front(); q.pop();
cur = Find(cur);
for (auto l : srcs[cur])
{
int ll = Find(l);
if (ll == cur) {
inconsist = true;
break;
}
if (--n_targets[ll] == 0)
q.push(ll);
}
if (inconsist) break;
}
if(!inconsist)
for(int i = 0; i < n; i++)
if (n_targets[i] > 0) {
inconsist = true;
break;
}
cout << (inconsist ? "inconsistent" : "consistent");
}
댓글남기기