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;
}
相关推荐
山北雨夜漫步1 小时前
机器学习 Day14 XGboost(极端梯度提升树)算法
人工智能·算法·机器学习
到底怎么取名字不会重复1 小时前
Day10——LeetCode15&560
c++·算法·leetcode·哈希算法·散列表
chuxinweihui1 小时前
数据结构——二叉树,堆
c语言·开发语言·数据结构·学习·算法·链表
freexyn2 小时前
Matlab自学笔记五十一:(推荐)输入参数的数量和可变数量的输入
笔记·算法·matlab
陈大大陈2 小时前
基于 C++ 的用户认证系统开发:从注册登录到Redis 缓存优化
java·linux·开发语言·数据结构·c++·算法·缓存
数据分析螺丝钉2 小时前
LeetCode 252 会议室 III(Meeting Rooms III)题解与模拟面试
算法·leetcode·职场和发展
小李独爱秋2 小时前
动态哈希映射深度指南:从基础到高阶实现与优化
数据结构·算法·哈希算法
猫猫头有亿点炸2 小时前
C语言斐波拉契数列2.0
c语言·开发语言·算法
写个博客3 小时前
代码随想录算法训练营第二十六天
算法
海底火旺3 小时前
寻找缺失的最小正整数:从暴力到最优的算法演进
javascript·算法·面试