双连通分量模板(点/边)

在一个无向图中,任意两个点都能通过至少两条不经过同一个点的路径而互相到达,就说明它是点双连通的。


点双连通分量:

割点满足条件:

LOW[G[i].v] >= DFN[x]

void Tarjan( int x , int fa ){
	int son = 0;
	DFN[x] = LOW[x] = ++index1;
	for( int i = head[x] ; ~i ; i = G[i].next1 ){
		if( !DFN[G[i].v] ){
			S.push(G[i]);   //存放边
			son ++ ;
			Tarjan( G[i].v , x );
			LOW[x] = min( LOW[x] , LOW[G[i].v] );
			if( LOW[G[i].v] >= DFN[x] ){
				iscut[x] = 1;
				++bcc_cnt;
				bcc[bcc_cnt].clear();
				while(1){
					Node tmp = S.top(); S.pop();
					if( bccno[tmp.u] != bcc_cnt ){
						bcc[bcc_cnt].push_back(tmp.u);
						bccno[tmp.u] = bcc_cnt;
					}
					if( bccno[tmp.v] != bcc_cnt ){
						bcc[bcc_cnt].push_back(tmp.v);
						bccno[tmp.v] = bcc_cnt;
					}
					if( tmp.u == x && tmp.v == G[i].v ){
						break;
					}
				}
			}
		}else{
			if( DFN[G[i].v] < DFN[x] && G[i].v != fa ){
				S.push(G[i]);
				LOW[x] = min( LOW[x] , DFN[G[i].v] );
			}
		}
	}
	if( fa < 0 && son == 1 ){
		iscut[x] = 0;
	}
}

void Find_Cut( ){
	bcc_cnt = 0;
	index1 = 0;
	memset( DFN , 0 ,sizeof(DFN) );    //编号
	memset( LOW , 0 ,sizeof(LOW) );    //可以达到的最前面的点
	memset( iscut , 0 ,sizeof(iscut) );
	memset( bccno , 0 ,sizeof(bccno) ); //存放每个点所处的连通分量中
	for( int i = 1 ; i <= n ; i++ ){
		if( !DFN[i] ){
			Tarjan( i , -1 );
		}
	}
}

边连通分量:

桥满足:

LOW[G[i].v] > DFN[x]

void tarjan( int x , int fa ){
	LOW[x] = DFN[x] = ++index;
	for( int i = head[x] ; ~i ; i = G[i].next1 ){
		if( !DFN[G[i].v] ){
			tarjan( G[i].v , x );
			LOW[x] = min( LOW[x] , LOW[G[i].v] );
			if( LOW[G[i].v] > DFN[x] ){
				cutEdge[i] = cutEdge[i^1] = 1;    //桥
			}
		}else if( G[i].v != fa ){
			LOW[x] = min( LOW[x] , DFN[G[i].v] );
		}
	}
} 


void Find_CutEage(){
	index = 0 ;
	memset( LOW , 0 , sizeof(LOW));
	memset( DFN , 0 , sizeof(DFN));
	memset( cutEdge , 0 , sizeof(cutEdge));
	for( int i = 1 ; i <= n ; i++ ){
		if( !DFN[i] ){
			tarjan( i , -1 );
		}
	}
}

 
  

你可能感兴趣的:(图论,割点割边)