https://www.acmicpc.net/problem/4196
4196번: 도미노
도미노는 재밌다. 도미노 블록을 일렬로 길게 늘어세운 뒤 블록 하나를 넘어뜨리면 그 블록이 넘어지며 다음 블록을 넘어뜨리는 일이 반복되어 일렬로 늘어선 블록들을 연쇄적으로 모두 쓰러
www.acmicpc.net
4196 도미노
알고리즘 : 강한연결요소(SCC)
SCC를 이용하여 사이클을 하나의 정점으로 만들어 위상정렬의 방식을 일부 따와서 푸는 문제입니다. 위상정렬은 사이클이 존재하면 풀리지 않으므로 SCC를 이용하여 사이클을 제거해주고 새로운 SCC에서 indegree가 0인 것을 카운팅 해주면 풀이됩니다.
< CODE >
#include <iostream>
#include <vector>
#include <stack>
#include <algorithm>
#include <queue>
using namespace std;
#define MAX 100005
int cnt = 0, cNum[MAX], result;
bool chk[MAX];
int isDomino[MAX];
vector<int> adj[MAX];
int SCC;
int sccInd[MAX];
stack<int> s;
int n, m;
void init()
{
cnt = 0;
result = 0;
SCC = 0;
for (int i = 0; i < MAX; i++)
{
chk[i] = false;
isDomino[i] = -1;
cNum[i] = 0;
adj[i].clear();
sccInd[i] = 0;
}
}
int dfs(int cur)
{
cNum[cur] = ++cnt;
s.push(cur);
int p = cNum[cur];
for (int i = 0; i < adj[cur].size(); i++)
{
int to = adj[cur][i];
if (!cNum[to])
p = min(p, dfs(to));
else if (!chk[to])
p = min(p, cNum[to]);
}
if (p == cNum[cur])
{
while (true)
{
int t = s.top(); s.pop();
isDomino[t] = SCC + 1;
chk[t] = true;
if (t == cur)
break;
}
SCC++;
}
return p;
}
void solve()
{
for (int i = 1; i <= n; i++)
{
for (int j = 0; j < adj[i].size(); j++)
{
int to = adj[i][j];
if (isDomino[i] != isDomino[to])
sccInd[isDomino[to]]++;
}
}
for (int i = 1; i <= SCC; i++)
{
if (sccInd[i] == 0)
result++;
}
}
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int tests;
cin >> tests;
while (tests--)
{
init();
cin >> n >> m;
for (int i = 0; i < m; i++)
{
int f, t;
cin >> f >> t;
adj[f].push_back(t);
}
for (int i = 1; i <= n; i++)
{
if(cNum[i] == 0)
dfs(i);
}
solve();
cout << result << '\n';
}
return 0;
}
시간 : 160ms
태그 : #BOJ 도미노 #4196 도미노 #백준 도미노 #도미노 풀이 #SCC #강한연결요소
'알고리즘' 카테고리의 다른 글
[BOJ / 2-SAT] 11281 2-SAT - 4 (0) | 2021.07.26 |
---|---|
[BOJ / 2-SAT] 11280 2-SAT - 3 (0) | 2021.07.25 |
[BOJ / 휴리스틱(시뮬레이티드 어닐링)] 2582 동전 뒤집기 2 (0) | 2021.07.19 |
[C++팁] 비트 개수 세는 함수 __popcnt / __builtin_popcount (0) | 2021.07.19 |
[BOJ / 인덱스 트리] 1572 중앙값 (0) | 2021.07.15 |