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;
}
相关推荐
吃好睡好便好6 小时前
用while循环语句求和
开发语言·学习·算法·matlab·信息可视化
王璐WL6 小时前
【C语言入门级教学】函数的概念2
c语言·数据结构·算法
不知名的忻7 小时前
B 树与 B+ 树:面试完全指南
b树·算法·面试·b+树
运筹vivo@8 小时前
2657. 找到两个数组的前缀公共数组 | 难度:中等
算法·leetcode·职场和发展·哈希表
索木木8 小时前
NCCL SHARP 和 TREE算法
java·服务器·算法
心中有国也有家9 小时前
hccl 架构拆解:昇腾集合通信库到底在做什么?
人工智能·经验分享·笔记·分布式·算法·架构
小O的算法实验室9 小时前
2026年MCS,Q-learning增强MOPSO与改进DWA融合算法+复杂三维地形下特定移动机器人动态路径规划
算法
Peter·Pan爱编程10 小时前
10. new_delete 不是 malloc_free 的包装
c++·人工智能·算法
故事和你9112 小时前
洛谷-【动态规划1】动态规划的引入2
开发语言·数据结构·c++·算法·动态规划·图论
重生之我是Java开发战士12 小时前
【动态规划】背包问题:完全背包,二位费用的背包问题,似包非包
算法·动态规划