【分离的路径 USACO 2006】(DCC | 边双连通分量 | 悬挂点 | 表思想 | 重边special judge | tarjan alg.)

jumper

题目大意:有n个旅游景点 r条路线,每条路线双向链接两个景区

由于每条线路都有可能被施工,并且保证每次施工只对一条线路进行。问至少需要添加几条边,能保证不论那条边在修建时,城市始终还是连通的

/*
*分离的路径 USACO 2006 jan.Gold / road construction POJ 3352
*/

#include 
#include 
#include 
#include 
#include 

#define _u first
#define _v second

using EDGE = std::pair;
constexpr int NN{(int)(1e5)};
std::vector edges{{0,0,},};
int head[NN+1]{0,},dfn[NN+1]{0,},Deg[NN+1]{0,},eBccID[NN+1]{0,},cnt = 0,TS = 0; 
std::vector eiTAB[NN+1]{{0,},};
std::stack stk;
std::bitset inStk;

inline void ADD(int u,int v){eiTAB[u].push_back(edges.size());edges.push_back({u,v});}

int tarjan(int u,int ei = -1){
	int lu,lv;
	dfn[u] = lu = ++TS;	
	inStk.set(u,(bool)1);
	int v;
	for(auto &nei:eiTAB[u]){
		v = edges[nei]._v;
		if(!((nei ^ 1) == ei)){
			if(!dfn[v]) lu = std::min(lu,lv = tarjan(v,nei));
			else lu = std::min(lu,dfn[nei]);
		}
	}
	if(!(lu == dfn[u]))return lu;
	int t = -1;++cnt;
	while(!(t == u)){
		t = stk.top();stk.pop();inStk.set(t,(bool)0);
		eBccID[t] = cnt;
	}
}

int contract(void){
	int ans = 0,x,y,i;
	for(auto &e:edges){
		x = eBccID[e._u],y = eBccID[e._v];
		if(!(x == y))++Deg[x],++Deg[y];
	}
	for(i = 1;i <= cnt;++i)ans += (int)(Deg[i] == 2);
	return ans;
}

int main(int argc,char const *argv[]){
	int N,M;
	scanf("%d%d",&N,&M);
	int u,v;
	while(M--){scanf("%d%d",&u,&v);ADD(u,v);ADD(v,u);}
	int leafs = contract();
	int i;
	for(i = 1;i <= N;++i)if(!dfn[i])tarjan(i);
	printf("%d\n",(leafs+1)/2);
	return 0;
}

你可能感兴趣的:(数据结构,算法,c++,图搜索,图论)