1. 程式人生 > >CCF——高速公路(有向強連通分量)

CCF——高速公路(有向強連通分量)

題目:

問題描述   某國有n個城市,為了使得城市間的交通更便利,該國國王打算在城市之間修一些高速公路,由於經費限制,國王打算第一階段先在部分城市之間修一些單向的高速公路。
  現在,大臣們幫國王擬了一個修高速公路的計劃。看了計劃後,國王發現,有些城市之間可以通過高速公路直接(不經過其他城市)或間接(經過一個或多個其他城市)到達,而有的卻不能。如果城市A可以通過高速公路到達城市B,而且城市B也可以通過高速公路到達城市A,則這兩個城市被稱為便利城市對。
  國王想知道,在大臣們給他的計劃中,有多少個便利城市對。 輸入格式   輸入的第一行包含兩個整數n, m,分別表示城市和單向高速公路的數量。
  接下來m行,每行兩個整數a, b,表示城市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。

思路:tarjan演算法 (目前這個演算法理解的不是很透徹,先貼程式碼吧

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<stack>
using namespace std;
#define MAX 10007
typedef long long ll;
vector<int> a[MAX];
stack<int> st;
int dfu[MAX],low[MAX];
bool b[MAX],is[MAX];
ll ans=0;

void dfs(int u){
	static int time=0;
	dfu[u]=low[u]=time++;
	st.push(u);
	is[u]=true;
	for(int i=0;i<a[u].size();++i){
		int v=a[u][i];
	    if(b[v] == false){
	    	b[v]=true;
	    	dfs(v);
	    	low[u]=min(low[u],low[v]);
	    }else if(is[v]){
	    	low[u]=min(low[u],dfu[v]);
	    }
	}
	
	//C(n,2)=n*(n-1)/2; 
	if(dfu[u] == low[u]){
		int cnt=0,v=0;
		do{
			v=st.top();
			is[v]=false;   //記得出棧後恢復 
			st.pop();
			cnt++;
		}while(u != v);
		ans += (cnt-1)*cnt/2;
	}
}
int main(){
    int n,m;
	cin>>n>>m;
	for(int i=0;i<m;++i){
		int x,y;
		cin>>x>>y;
		a[x].push_back(y);
	}
	//圖可能不是連通,所以只從某一點搜,不一定能搜整個圖 
	for(int i=1;i<=n;++i)
	    if(b[i] == false){
		    b[i]=true;
			dfs(i);
		}
		
	cout<<ans<<endl; 
	return 0;
}

)