无向图找桥

无向图找桥(参考的一个acm模板,不知道挂啥链接)

算法思想:
  1. 设置vis, pre, anc数组。
    • pre[cur]:cur结点dfs时访问时的时间’。
    • anc[cur]: 记录cur结点及其子孙结点最早祖先的dfs时间(朔源到尽头)。
    • vis标记结点访问状态:0:未访问, 1:正在访问, 2:访问结束。
  2. 访问当前结点cur时,通过其子孙递归的更新其最早祖先的dfs时间,找出所有桥。dfs过程中,其孩子节点child如果还未开始访问则child为树边,递归;若已经开始访问且未结束,且不是cur父亲,则此节点为cur的祖先,可以更新anc[cur]。
  3. 对于cur -> child,anc[child] > pre[cur] 得出 child -> cur为桥。证明:anc[child] > pre[cur]表示child及其任意子孙,能溯源到的最早时间晚于cur结点,于是child及其子孙无法通过任何途径到达cur结点(除了child -> cur)。

题目链接

邻接矩阵版
/*==================================================*\
 | 无向图找桥(删除桥后图不连通)
 | INIT: edge[][]邻接矩阵;vis[],pre[],anc[],bridge 置0;
 | CALL: dfs(0, -1, 1, n);
 | Tarjan算法
\*==================================================*/
int edge[V][V], anc[V], pre[V], vis[V]; 
vector<vector<int> > ans;
void dfs(int cur, int father, int dep, int n){ 			// vertex: 0 ~ n-1
	vis[cur] = 1;		//开始访问
	pre[cur] = anc[cur] = dep; 
	for(int i = 0; i < n; ++i) 
		if(edge[cur][i]){ 
 			if(i != father && 1 == vis[i]){ 	//i访问还未结束,所以为cur的祖先
 				if(pre[i] < anc[cur]) 			//更新cur的最早祖先
					anc[cur] = pre[i];			//back edge
 			} 
 			if(0 == vis[i]){ 					//tree edge,i还未访问,搜索树的树边
				dfs(i, cur, dep+1, n); 
 				if(anc[i] < anc[cur])			//如果cur的最小祖先大于i的最小祖先,且存在cur->i,则更新
		 			anc[cur] = anc[i]; 			//cur的最小祖先
	 			if(anc[i] > pre[cur])			//如果cur的搜索时间比child的最早的祖先时间还小则找到一条桥
					ans.push_back({cur, child}); 
			} 
 		} 
 	vis[cur] = 2; 		//结束访问
} 
邻接表版
int anc[V], pre[V], vis[V]; 
vector<vector<int> > ans;
vector<int> adj[V];
void dfs(int cur, int father, int dep, int n){ 			// vertex: 0 ~ n-1 
	vis[cur] = 1;		//开始访问
	pre[cur] = anc[cur] = dep; 
	for(int i = 0; i < adj[cur].size(); ++i){ 
		int child = adj[cur][i];
 		if(child != father && 1 == vis[child]){ 	//child访问还未结束,所以为cur的祖先
 			if(pre[child] < anc[cur]) 				//更新cur的最早祖先
				anc[cur] = pre[child];			//back edge
 		} 
 		if(0 == vis[child]){ 					//tree edge, child还未访问,搜索树的树边
			dfs(child, cur, dep+1, n); 
 			if(anc[child] < anc[cur])			//如果cur的最小祖先大于child的最小祖先,且存在cur->child,
		 		anc[cur] = anc[child]; 			//则更新cur的最小祖先
	 		if(anc[child] > pre[cur])			//如果cur的搜索时间比child的最早的祖先时间还小则找到一条桥
				ans.push_back({cur, child}); 
		} 
 	} 
 	vis[cur] = 2; 		//结束访问
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值