CCF 201509-4 高速公路(100分)

Enjoy_process發表於2018-09-06
試題編號: 201509-4
試題名稱: 高速公路
時間限制: 1.0s
記憶體限制: 256.0MB
問題描述:

問題描述

  某國有n個城市,為了使得城市間的交通更便利,該國國王打算在城市之間修一些高速公路,由於經費限制,國王打算第一階段先在部分城市之間修一些單向的高速公路。
  現在,大臣們幫國王擬了一個修高速公路的計劃。看了計劃後,國王發現,有些城市之間可以通過高速公路直接(不經過其他城市)或間接(經過一個或多個其他城市)到達,而有的卻不能。如果城市A可以通過高速公路到達城市B,而且城市B也可以通過高速公路到達城市A,則這兩個城市被稱為便利城市對。
  國王想知道,在大臣們給他的計劃中,有多少個便利城市對。

輸入格式

  輸入的第一行包含兩個整數nm,分別表示城市和單向高速公路的數量。
  接下來m行,每行兩個整數ab,表示城市a有一條單向的高速公路連向城市b

輸出格式

  輸出一行,包含一個整數,表示便利城市對的數量。

樣例輸入

5 5
1 2
2 3
3 4
4 2
3 5

樣例輸出

3

樣例說明


  城市間的連線如圖所示。有3個便利城市對,它們分別是(2, 3), (2, 4), (3, 4),請注意(2, 3)和(3, 2)看成同一個便利城市對。

評測用例規模與約定

  前30%的評測用例滿足1 ≤ n ≤ 100, 1 ≤ m ≤ 1000;
  前60%的評測用例滿足1 ≤ n ≤ 1000, 1 ≤ m ≤ 10000;
  所有評測用例滿足1 ≤ n ≤ 10000, 1 ≤ m ≤ 100000。 

問題連線:CCF 201509-4 高速公路

題解:有向圖強連通分支模板題

AC的C++程式碼:

#include<iostream>
#include<vector>
#include<stack>

using namespace std;
const int N=10010;
vector<int>g[N];
stack<int>s;

bool flag[N];//標記結點是否在棧內 
int dfn[N],low[N];
int index;
long long ans;

void Tarjan(int u)
{
	dfn[u]=low[u]=++index;
	s.push(u);
	flag[u]=true;//記錄結點u在棧內 
	for(int i=0;i<g[u].size();i++){
		int v=g[u][i];
		if(!dfn[v]){//如果結點v沒有被訪問 
	  	  Tarjan(v);
	  	  low[u]=min(low[u],low[v]);
	    }
	    else if(flag[v])//如果v被訪問並且在棧內 
	      low[u]=min(low[u],dfn[v]);
	}
	if(dfn[u]==low[u]){//u是一個強連通分量的根
	    int num=0,v;
		do{
			num++;
			v=s.top();
			s.pop();
			flag[v]=false;//記錄v不再棧中 
		}while(u!=v);//退棧,把整個強連通分量都彈出來 
		if(num>1)
		  ans+=(num-1)*num/2; 
	} 
}

int main()
{
	int n,m,a,b;
	scanf("%d%d",&n,&m);
	while(m--){
		scanf("%d%d",&a,&b);
		g[a].push_back(b);
	}
	for(int i=1;i<=n;i++)
	  if(!dfn[i])//如果結點i沒有被訪問 
	  	Tarjan(i);
	printf("%lld\n",ans);
	return 0;
}

 

相關文章