https://www.acmicpc.net/problem/18133

 

18133번: 가톨릭대학교에 워터 슬라이드를??

두 정수 N (2 ≤ N ≤ 100,000), M (1 ≤ M ≤ 100,000)이 주어진다. N 은 건물의 개수를, M 은 터널의 개수를 나타낸다. 건물 옥상들의 번호는 1과 N 사이의 정수다. 다음 M개의 줄에는 각각 두 정

www.acmicpc.net

문제를 풀기전에 Disjoint SetSCC를 공부해오는 걸 추천드립니다!!

 

풀이

더보기

먼저 그래프를 그려볼게요

 

4  3
1  2
2  1
3  1

 

 

1,2번 노드로 가는 통로는 있지만

3,4번으로 가는 통로는 없습니다.

어디에 물을 넣어주던 3,4번에는 각각 물을 넣어줘야됩니다.

 

즉, 자신에게 오는 통로가 없는 노드에 먼저 물을 다 넣어줘야됩니다.

  

하지만 이러한 경우도 존재합니다.

 

 

 

모두 자신에게 오는 경로가 존재합니다. 

그래프끼리 사이클을 형성하는 경우가 존재하기 때문입니다.

잘 생각해보면 사이클을 형성하는 그래프를 하나의 노드로 생각할수 있습니다.

SCC를 이용해 사이클을 찾습니다.

 

 

 

그후 사이클을 형성하는 노드끼리 Disjoint Set으로 묶어 하나의 노드로 먼저 만든 후

다시 자신에게 오는 통로가 없는 노드에 먼저 물을 넣으면 됩니다.

 

 

코드

더보기
#include <bits/stdc++.h>

using namespace std;

#define endl "\n"
#define int long long
#define float double

int N, M;
bool Visit[100001];
vector<int> A[100001];
vector<int> B[100001];
stack<int> STACK;
vector<vector<int>> Group;

int P[100001];
int FindP(int a)
{
	if (P[a] == a)
		return a;
	else
	{
		int emp = FindP(P[a]);
		P[a] = emp;
		return emp;
	}
}

void Union(int a, int b)
{
	P[FindP(b)] = P[FindP(a)];
}

void DFS_A(int n)
{
	Visit[n] = true;
	for (int i = 0; i < A[n].size(); i++)
	{
		int next = A[n][i];
		if (Visit[next])
			continue;
		DFS_A(next);
	}
	STACK.push(n);
}

void DFS_B(int n, vector<int>& SCC)
{
	Visit[n] = true;
	SCC.push_back(n);
	for (int i = 0; i < B[n].size(); i++)
	{
		int next = B[n][i];
		if (Visit[next])
			continue;
		DFS_B(next, SCC);
	}
}

bool ComeNode[100001];

int32_t main()
{
	ios_base::sync_with_stdio(false);
	cin.tie(NULL);
	cout.tie(NULL);

	cin >> N >> M;
	for (int i = 0; i < M; i++)
	{
		int a, b;
		cin >> a >> b;
		A[a].push_back(b);
		B[b].push_back(a);
	}
	for (int i = 1; i <= N; i++)
		P[i] = i;

	for (int i = 1; i <= N; i++)
		if (!Visit[i])
			DFS_A(i);

	memset(Visit, false, sizeof(Visit));

	while (!STACK.empty())
	{
		vector<int> temp;
		int next = STACK.top();
		STACK.pop();
		if (Visit[next])
			continue;
		DFS_B(next, temp);
		Group.push_back(temp);
	}

	for (int i = 0; i < Group.size(); i++)
		for (int j = 1; j < Group[i].size(); j++)
			Union(Group[i][0], Group[i][j]);

	int ans = 0;

	for (int i = 1; i <= N; i++)
		for (int j = 0; j < A[i].size(); j++)
		{
			int a = FindP(i);
			int b = FindP(A[i][j]);
			if (a != b)
				ComeNode[b] = true;
		}

	memset(Visit, false, sizeof(Visit));

	for (int i = 1; i <= N; i++)
	{
		int a = FindP(i);
		if (!Visit[a] && !ComeNode[a])
		{
			DFS_A(a);
			ans++;
		}
	}

	cout << ans << endl;
}

 

-----------------------------------------------------------------------------------------------------------------------------------

질문은 언제나 환영합니다.

'알고리즘 > 문제풀이' 카테고리의 다른 글

백준 1062 가르침  (0) 2021.07.08
백준 21967 세워라 반석 위에  (0) 2021.06.18
백준 11062 카드게임  (0) 2021.06.03
백준 2342번 Dance Dance Revolution  (0) 2021.06.03
백준 2579번 계단 오르기  (0) 2021.06.02

+ Recent posts