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;
}
相关推荐
C_player_00129 分钟前
——贪心算法——
c++·算法·贪心算法
kyle~2 小时前
排序---插入排序(Insertion Sort)
c语言·数据结构·c++·算法·排序算法
Boop_wu2 小时前
[数据结构] 队列 (Queue)
java·jvm·算法
hn小菜鸡2 小时前
LeetCode 3643.垂直翻转子矩阵
算法·leetcode·矩阵
ゞ 正在缓冲99%…3 小时前
leetcode101.对称二叉树
算法
YuTaoShao4 小时前
【LeetCode 每日一题】3000. 对角线最长的矩形的面积
算法·leetcode·职场和发展
2zcode4 小时前
基于Matlab可见光通信系统中OOK调制的误码率性能建模与分析
算法·matlab·php
纵有疾風起4 小时前
数据结构中的排序秘籍:从基础到进阶的全面解析
c语言·数据结构·算法·排序算法
纪元A梦4 小时前
贪心算法应用:推荐冷启动问题详解
算法·贪心算法
听风说雨的人儿4 小时前
腾讯面试题之编辑距离
算法