Tarjan模板题求割点,桥

本文介绍如何使用Tarjan算法求解无向图中的割点和桥的问题。通过两个具体的UVa在线评测系统题目实例,分别展示了如何求解割点数量及如何找出所有的桥。提供了完整的代码实现及解析。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

模板题:Tarjan算法求割点,桥

  1.  UVA - 796 Critical Links Tarjan求割点个数

题目链接Vjudge 
题意: 给定N个顶点若干条边, 求割点个数。
思路:模板题。套用kuangbin大牛的 Tarjan 模板。
#include <bits/stdc++.h>
using namespace std;

#define FIN             freopen("input.txt","r",stdin)
#define FOUT            freopen("output.txt","w",stdout)
#define fst             first
#define snd             second

const int MAXN = 100 + 5;
const int MAXM = MAXN * MAXN * 2 + 5;
struct Edge {
	int v, next;
	Edge() {}
	Edge(int v, int next) : v(v), next(next) {}
} edge[MAXM];
int head[MAXN], tot;
int low[MAXN], dfn[MAXN], add_block[MAXN];
int Index;
int N, res;
char buf[300];

void add_edge(int u, int v) {
	edge[tot] = Edge(v, head[u]);
	head[u] = tot++;
}
void Tarjan(int u, int pre) {
	int v, son = 0;
	low[u] = dfn[u] = ++Index;
	for (int i = head[u]; ~i; i = edge[i].next) {
		v = edge[i].v;
		if (v == pre) continue;
		if (!dfn[v]) {
			son ++;
			Tarjan(v, u);
			low[u] = min(low[u], low[v]);
			if (u != pre && low[v] >= dfn[u]) {
				add_block[u] ++;
			}
		} else {
			low[u] = min(low[u], dfn[v]);
		}
		if (u == pre) {
			add_block[u] = son - 1;
		}
	}
}
void init() {
	tot = 0;
	memset(head, -1, sizeof(head));
	memset(dfn, 0, sizeof(dfn));
	memset(add_block, 0, sizeof(add_block));
	Index = res = 0;
}
int main() {
#ifndef ONLINE_JUDGE
	FIN;
#endif // ONLINE_JUDGE
	while (~scanf("%d\n", &N) && N) {
		int u, v;
		init();
		while (gets(buf) != NULL) {
			if (buf[0] == '0') break;
			char* p = strtok(buf, " ");
			sscanf(p, "%d", &u);
			p = strtok(NULL, " ");
			while (p) {
				sscanf(p, "%d", &v);
				p = strtok(NULL, " ");
				add_edge(u, v);
				add_edge(v, u);
			}
		}
		for (int i = 1; i <= N; i++) {
			if (!dfn[i]) Tarjan(i, i);
		}
		for (int i = 1; i <= N; i++) {
			if (add_block[i]) res ++;
		}
		printf("%d\n", res);
	}
	return 0;
}

  1. UVA - 796 Critical Links Tarjan求桥


题目链接Vjudge
题意:给定若干顶点,和若干条边组成的无向图,求桥的个数,并且依次打印出每条桥的两个端点。顶点个数题目没有给出,测试在100个顶点以内吧。注意每组数据输出空行。结果保存在set中,去重。
#include <bits/stdc++.h>
using namespace std;

#define FIN             freopen("input.txt","r",stdin)
#define FOUT            freopen("output.txt","w",stdout)
#define fst             first
#define snd             second
typedef pair<int, int>	PII;

const int MAXN = 100 + 5;
const int MAXM = MAXN * MAXN * 2 + 5;

struct Edge {
	int v, next;
	bool cut;
	Edge() {}
	Edge(int v, int next, bool cut) : v(v), next(next), cut(cut) {}
} edge[MAXM];
int head[MAXN], tot;
int low[MAXN], dfn[MAXN];
int Index, top;
int bridge;
int N, M;
set<PII> res;

void add_edge(int u, int v) {
	edge[tot] = Edge(v, head[u], false);
	head[u] = tot++;
}
void Tarjan(int u, int pre) {
	int v;
	low[u] = dfn[u] = ++Index;
	for (int i = head[u]; ~i; i = edge[i].next) {
		v = edge[i].v;
		if (v == pre) continue;
		if (!dfn[v]) {
			Tarjan(v, u);
			low[u] = min(low[u], low[v]);
			if (low[v] > dfn[u]) {
				bridge++;
				edge[i].cut = true;
				edge[i ^ 1].cut = true;
				res.insert(make_pair(min(u, v), max(u, v)));
			}
		} else if (low[u] > dfn[v]) {
			low[u] = dfn[v];
		}
	}
}
void init() {
	tot = Index = 0;
	bridge = 0;
	memset(dfn, 0, sizeof(dfn));
	memset(head, -1, sizeof(head));
	res.clear();
}
int main() {
#ifndef ONLINE_JUDGE
	FIN;
#endif // ONLINE_JUDGE
	int u, v;
	while (~scanf("%d", &N)) {
		init();
		for (int i = 0; i < N; i++) {
			scanf("%d (%d)", &u, &M);
			while (M --) {
				scanf("%d", &v);
				add_edge(u, v);
				add_edge(v, u);
			}
		}
		for (int i = 0; i < N; i++) {
			if (!dfn[i]) Tarjan(i, i);
		}
		printf("%d critical links\n", bridge);
		for (set<PII>::iterator iter = res.begin(); iter != res.end(); iter++) {
			printf("%d - %d\n", (*iter).fst, (*iter).snd);
		}
		puts("");
	}
	return 0;
}

### 关于顶)问题的解决方案 在图论中,是指如果删除该节及其相连的所有边会使图分裂成两个或更多互不连接的部分。识别这些关键节对于网络可靠性分析至关重要。 #### Tarjan算法用于寻找 Tarjan算法是一种基于深度优先搜索(DFS)的方法,能够高效地找出所有的[^4]。以下是具体实现: ```cpp #include <vector> using namespace std; const int MAXN = 1e5 + 7; int dfn[MAXN], low[MAXN]; bool cut_vertex[MAXN]; // 记录是否为 vector<int> adj[MAXN]; void tarjan(int u, int parent, vector<bool>& visited, int& timestamp){ visited[u] = true; dfn[u] = low[u] = ++timestamp; int children = 0; for(auto v : adj[u]){ if(!visited[v]){ children++; tarjan(v, u, visited, timestamp); low[u] = min(low[u], low[v]); // 判断条件:根结至少有两个子节 或 非根结满足low[v]>=dfn[u] if(parent != -1 && low[v] >= dfn[u]) cut_vertex[u] = true; if(parent == -1 && children > 1) cut_vertex[u] = true; } else if(v != parent){ // 反向边 low[u] = min(low[u], dfn[v]); } } } ``` 此代码片段展示了如何使用Tarjan算法来检测给定无向图中的所有。`cut_vertex[]`数组用来标记哪些顶点;而`adj[][]`则存储邻接表形式表示的输入图。 为了初始化上述过程,还需要设置一些辅助变量,并调用函数遍历整个图: ```cpp // 初始化全局变量 memset(dfn, 0, sizeof(dfn)); memset(cut_vertex, false, sizeof(cut_vertex)); for(int i=1;i<=nodes;++i){ if(!dfn[i]){ int time_stamp = 0; vector<bool> vis(nodes+1,false); tarjan(i,-1,vis,time_stamp); } } ``` 这段程序会依次访问每一个未被探索过的节作为起执行一次完整的tarjan搜索流程,从而确保覆盖到整张图上的全部可能存在的情况。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值