baekjoon

[백준] 2152 여행 계획 세우기

윤만석 2023. 2. 3. 15:01

문제

평소 일로 바쁘던 태희는 휴가를 통해 여행을 다녀오기로 하였다. 우선 태희는 사전 조사를 통해서 여행하려는 도시를 N(1 ≤ N ≤ 10,000)개 선택하였다. 태희는 비행기를 이용하면 충분히 여행할 수 있을거라 생각했지만, 짐을 꾸리던 중 비행기가 모든 도시들 사이를 다니는 것은 아님을 알게 되었다.

태희는 다시 비행로에 대해 조사를 하였고, 총 M(1 ≤ M ≤ 100,000)개의 비행로가 존재함을 알게 되었다. 각각의 비행로는 한 방향으로의 서비스만을 제공한다. 태희는 S(1 ≤ S ≤ N)번 도시에서 시작해서 T(1 ≤ T ≤ N)번 도시에서 여행을 끝내기로 하였다. 그리고 태희는 도시와 항공로에 대한 정보를 바탕으로 여행 계획을 세우기로 하였다.

도시와 비행로에 대한 정보가 주어졌을 때, S번 도시에서 T번 도시로 여행을 할 때 최대로 방문할 수 있는 도시의 개수를 구하는 프로그램을 작성하시오. 각각의 도시는 여행 중에 몇 번이든 방문할 수 있으며, 같은 항공로를 여러 번 이용할 수도 있다. 물론 같은 도시를 여러 번 방문하는 경우는 한 번만 생각하기로 한다.

입력

첫째 줄에 네 정수 N, M, S, T가 주어진다. 다음 M개의 줄에는 각각의 비행로에 대한 정보를 나타내는 서로 다른 두 정수 A, B(1 ≤ A, B ≤ N)가 주어진다. 이는 A번 도시에서 B번 도시로 이동하는 항공로가 존재함을 의미한다.

출력

첫째 줄에 방문할 수 있는 도시의 최대 개수를 출력한다. 만약 여행 계획을 목표대로 세울 수 없다면 0을 출력한다.

 

출발도시부터 도착도시에 도착할때까지, 간선은 여러번 이용가능하며 최대 얼마나 많은 도시를 방문할 수 있는지 묻는 문제입니다.

간선을 여러번 이용가능하기때문에, 정점(도시)간 이어진 간선이 사이클을 이룬다면 그 사이클에 도착만하면 사이클 안의 모든 도시를 방문할 수 있습니다.

따라서 scc로 구성된 단방향그래프 DAG를 그리고, DP를 이용하면 몇개의 SCC를 지날 수 있는지 구할 수 있고, 따라서 총 몇개의 도시를 지날 수 있는지 구할 수 있습니다.

#include<bits/stdc++.h>

using namespace std;
int N, M, S, T, a, b, v[10001], dp[10001], s[10001], n[10001], cnt, num, m;
vector<int>adj[10001], adj2[10001], st;
int dfs(int k) {
	st.push_back(k);
	int parent = v[k] = ++cnt;
	for (auto r : adj[k]) {
		if (!v[r]) {
			parent = min(parent, dfs(r));
		}
		else if (!s[r]) {
			parent = min(parent, v[r]);
		}
	}
	if (parent == v[k]) {
		num++;
		while (1) {
			auto top = st.back();
			s[top] = num;
			n[num]++;
			st.pop_back();
			if (top == k)break;
		}
	}
	return parent;
}
void tarjan() {
	for (int i = 1; i <= N; i++)
		if (!v[i])dfs(i);
}

int dfs2(int k) {
	if (dp[k])return dp[k];

	for (auto r : adj2[k]) {
		auto c = dfs2(r);
		if (c)
			dp[k] = max(dp[k], n[k] + c);
	}

	return dp[k];
}

void solve() {
	
	for (int i = 1; i <= N; i++) {
		for (auto r : adj[i]) {
			if (s[i] != s[r]) {
				adj2[s[i]].push_back(s[r]);
			}
		}
		sort(adj2[s[i]].begin(), adj2[s[i]].end());
		adj2[s[i]].erase(unique(adj2[s[i]].begin(), adj2[s[i]].end()), adj2[s[i]].end());
	}
	dp[s[T]] = n[s[T]];
	dfs2(s[S]);
}
int main() {
	ios_base::sync_with_stdio(false);
	cin.tie(NULL);
	cin >> N >> M >> S >> T;
	while (M--) {
		cin >> a >> b;
		adj[a].push_back(b);
	}
	tarjan();
	solve();
	cout << dp[s[S]];
}