hdu.Railway,点双联通分量 + 桥(割边),tarjan算法

Problem - 3394 (hdu.edu.cn)

Railway

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 6294 Accepted Submission(s): 2055

Problem Description
There are some locations in a park, and some of them are connected by roads. The park manger needs to build some railways along the roads, and he would like to arrange tourist routes to each circuit. If a railway belongs to more than one tourist routes, there might be clash on it, and if a railway belongs to none tourist route, it doesn't need to build.
Now we know the plan, and can you tell us how many railways are no need to build and how many railways where clash might happen.

Input
The Input consists of multiple test cases. The first line of each test case contains two integers, n (0 < n <= 10000), m (0 <= m <= 100000), which are the number of locations and the number of the railways. The next m lines, each line contains two integers, u, v (0 <= u, v < n), which means the manger plans to build a railway on the road between u and v.
You can assume that there is no loop and no multiple edges.
The last test case is followed by two zeros on a single line, which means the end of the input.

Output
Output the number of railways that are no need to build, and the number of railways where clash might happen. Please follow the format as the sample.

Sample Input

复制代码

8 10
0 1
1 2
2 3
3 0
3 4
4 5
5 6
6 7
7 4
5 7
0 0

Sample Output

复制代码

1 5

Author
momodi@whu

题解

对于一个点双联通子图,如果边的个数等于点的个数,那么该点双联通子图刚好形成一个环;如果边的个数大于点的个数,那么该点双联通子图至少存在三个环,且每一条边都至少存在于两个环中,所以该子图的所有边都为冲突边

桥为多余的边

注意:这道题中会有重边

cpp 复制代码
#include<iostream>
#include<string>
#include<cstring>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<utility>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<math.h>
#include<map>
using namespace std;
typedef long long LL;
const int N = 1e4 + 5, M = 2e5 + 5;
int n, m;
int h[N], e[M], ne[M], idx;
int dfn[N], low[N], timestamp;
int id[N], siz[N],  dcc_cnt;
int ans1,ans;
stack<pair<int,int>>st;
set<int>pos[N];


void add(int a, int b) {
	e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}

void tarjan(int u,int fa) {
	dfn[u] = low[u] = ++timestamp;
	for (int i = h[u]; i != -1; i = ne[i]) {
		int j = e[i];
		if (!dfn[j]) {
			st.push({u,j});
			tarjan(j, i);
			low[u] = min(low[u], low[j]);
			if (low[j] >= dfn[u]) {
				dcc_cnt++;
				id[u] = dcc_cnt;
				pos[dcc_cnt].clear();
				while (1)
				{
					auto t = st.top();
					st.pop();
					siz[dcc_cnt]++;//存某个连通图中的边数
					pos[dcc_cnt].insert(t.first), pos[dcc_cnt].insert(t.second);//存编号为i的连通图中包含的点数
					if (u == t.first && j == t.second)break;
				}
			}
			if (dfn[u] <low[j]) {
				ans1++;
			}
		}
		else if (i != (fa ^ 1) && dfn[j] < dfn[u]) {
			st.push({ u,j });
			low[u] = min(low[u], dfn[j]);
		}
	}
}

int main() {
	while (cin >> n >> m,n||m) {
		memset(h, -1, sizeof h);
		memset(dfn, 0, sizeof dfn);
		memset(siz, 0, sizeof siz);
		idx = timestamp = dcc_cnt = ans1 = ans = 0;
		for (int i = 1,a,b; i <= m; i++) {
			scanf("%d%d", &a, &b);
			add(a, b), add(b, a);
		}
		for (int i = 0; i < n; i++) {
			if (!dfn[i])
				tarjan(i,-1);
		}
		for (int i = 1; i <= dcc_cnt; i++) {
			if (siz[i] > pos[i].size()) {
				ans += siz[i];
			}
		}
		cout << ans1 << " " << ans << endl;
	}
	return 0;
}
相关推荐
古月居GYH4 分钟前
数据结构算法——排序算法解析
数据结构·算法·排序算法
Zzzzmo_12 分钟前
【Java】排序算法(思路及图解)
算法·排序算法
人得思变~谁会嫌自己帅呢?14 分钟前
希尔排序算法
数据结构·算法·排序算法
福尔摩斯张19 分钟前
C语言文件操作详解(一):文件的打开与关闭(详细)
java·linux·运维·服务器·c语言·数据结构·算法
white-persist20 分钟前
【攻防世界】reverse | answer_to_everything 详细题解 WP
c语言·开发语言·汇编·python·算法·网络安全·everything
Ynchen. ~28 分钟前
[工程实战] 攻克“数据孤岛”:基于隐语纵向联邦学习的金融风控建模全解析
算法·金融·逻辑回归·隐语
程序员-King.31 分钟前
day107—同向双指针—无重复字符的最长字串(LeetCode-3)
算法·leetcode·双指针
风掣长空31 分钟前
【LeetCode】面试经典150题:合并两个有序数组
算法·leetcode·面试
im_AMBER34 分钟前
Leetcode 69 正整数和负整数的最大计数
数据结构·笔记·学习·算法·leetcode
fufu031136 分钟前
Linux环境下的C语言编程(三十六)
linux·c语言·开发语言·数据结构·算法