CCF認證201509-4高速公路

原題鏈接

CCF認證201509-4高速公路

解題思路

最強連通子圖[Tarjan算法]

dfn[u]爲節點u的次序編號(時間戳)
low[u[爲u或u的子樹能夠追溯到的最早的棧中節點的次序號
當dfn[u]=low[u]時,以u爲根的搜索子樹上的所有節點是一個強連通分量

僞代碼
tarjan(u){
	dfn[u] = low[u] = ++index;//時間戳
	s.push(u);
	for each(u,v) in E
		if (v is not visited)//節點v未被訪問過 
			targan(v)
			low[u] = min(low[u],low[v]);
		else if(v in s) //節點v還在棧中
			low[u] = min(low[u],dfn[v]);
	if dfn[u] == low[u]  //節點u是強連通分量的跟
		repeat
			v = s.pop  //將v進行退棧 ,爲改連通分量的一個頂點 
			print v
		until u == v 
}

代碼

#include <bits/stdc++.h>
using namespace std;
const int maxn = 10010;
vector<int> graph[maxn];
bool ins[maxn];//標記是否在棧中 
int dfn[maxn],low[maxn];
int ans=0;
int index = 0;
stack<int> s;
void tarjan(int u){
	dfn[u] = low[u] = ++index;//時間戳
	ins[u] = true;
	s.push(u);
	for(int i=0;i<graph[u].size();i++){
		int v = graph[u][i];
		if(dfn[v]==0){
			tarjan(v);
			low[u] = min(low[u],low[v]);
		}else if(ins[v]){//在堆棧中 
			low[u] = min(low[u],dfn[v]);
		}
	} 
	if(low[u] == dfn[u]){
		//出棧
		int cnt = 0,t;	
		do{
			t = s.top();
			s.pop();
			ins[t] = false;
			cnt ++;			
		}while(t != u);
		ans += cnt*(cnt-1)/2; 
	} 
}
int main(){
	int n,m;
	scanf("%d%d",&n,&m);
	for(int i=0;i<m;i++){
		int a,b;
		scanf("%d%d",&a,&b);
		graph[a].push_back(b);
	}
	for(int i=1;i<=n;i++){
		if(dfn[i]==0){
			tarjan(i);
		}
	}
	cout<<ans;
	return 0;
} 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章