Skip to content

Latest commit

 

History

History
107 lines (82 loc) · 1.88 KB

021.md

File metadata and controls

107 lines (82 loc) · 1.88 KB

021 - Come Back in One Piece (★5)

解答

#include <iostream>
#include <vector>
#include <algorithm> // std::reverse(), std::fill()

using Graph = std::vector<std::vector<int>>;

void DFS(const Graph& g, int from, std::vector<bool>& visited, std::vector<int>& results)
{
	visited[from] = true;

	for (const auto& to : g[from])
	{
		if (!visited[to])
		{
			DFS(g, to, visited, results);
		}
	}

	// 帰りがけ順に頂点を記録
	results.push_back(from);
}

void DFS2(const Graph& g, int from, long long& count, std::vector<bool>& visited)
{
	visited[from] = true;

	++count;

	for (const auto& to : g[from])
	{
		if (!visited[to])
		{
			DFS2(g, to, count, visited);
		}
	}
}

int main()
{
	// N 頂点, M 辺
	int N, M;
	std::cin >> N >> M;

	// 入力されたグラフ
	Graph g1(N);
	
	// 辺の向きを反転したグラフ
	Graph g2(N);

	for (int i = 0; i < M; ++i)
	{
		int from, to;
		std::cin >> from >> to;
		--from;
		--to;

		g1[from].push_back(to);
		g2[to].push_back(from);
	}

	// 頂点が訪問済みか記録する配列
	std::vector<bool> visited(N);

	// 帰りがけ順に頂点を記録する配列
	std::vector<int> results;

	for (int i = 0; i < N; ++i)
	{
		if (!visited[i])
		{
			DFS(g1, i, visited, results);
		}
	}

	// 帰りがけ順が大きい頂点から処理するため並び順を反転
	std::reverse(results.begin(), results.end());

	// 次の探索のために、訪問済み頂点をリセット
	std::fill(visited.begin(), visited.end(), false);

	long long answer = 0;

	for (int from : results)
	{
		if (visited[from])
		{
			continue;
		}
		
		long long count = 0;

		// 行き止まりになるまでの頂点数を count に記録
		DFS2(g2, from, count, visited);

		// そのグループの頂点数から、answer に追加するペア数を求める
		answer += (count * (count - 1) / 2);
	}

	// 解答を出力
	std::cout << answer << '\n';
}