Official

C - Tour Editorial by kyopro_friends


スタート地点を固定したときゴール地点にできる都市の個数を数えることを考えてみましょう。

ゴール地点にできる都市は、スタート地点からいくつかの道路を使って到達できるような都市です。そのような都市は、DFSやBFSなどの探索アルゴリズムを用いて求めることができます。この際、既にチェックした頂点を2度以上調べないようにすることで、\(O(N+M)\) で求めることができます。

どの都市をスタート地点とするか \(N\) 通り全てを試すことで、全体で \(O(N(N+M))\) で問題が解けました。

実装例(Python)

# おまじない
import sys
sys.setrecursionlimit(10000)

# 入力の読み込み
N,M=map(int,input().split())
G=[[] for i in range(N)]
# G[i] は都市iから道路で直接繋がっている都市のリスト
for i in range(M):
  A,B=map(int,input().split())
  G[A-1].append(B-1)

# dfs
def dfs(v):
  if temp[v]: return  # 同じ頂点を2度以上調べないためのreturn
  temp[v]=True
  for vv in G[v]: dfs(vv)

ans=0

# 都市iからスタートする場合
for i in range(N):
	temp=[False]*N
	# temp[j] は都市jに到達可能かどうかを表す
	dfs(i)
	ans+=sum(temp)

print(ans)

実装例(C++)

#include<bits/stdc++.h>
using namespace std;
const int MAX_N=2000;

vector<vector<int>>G;
bool temp[MAX_N];
void dfs(int v){
	if(temp[v])return;
	temp[v]=true;
	for(auto vv:G[v])dfs(vv);
}

int main(){
	int N,M;
	cin >> N >> M;
	G.resize(N);
	for(int i=0;i<M;i++){
		int a,b;
		cin >> a >> b;
		G[a-1].push_back(b-1);
	}

	int ans=0;
	for(int i=0;i<N;i++){
		for(int j=0;j<N;j++)temp[j]=false;
		dfs(i);
		for(int j=0;j<N;j++)if(temp[j])ans++;
	}
	
	cout << ans;
}

posted:
last update: