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;
}
相关推荐
这张生成的图像能检测吗18 分钟前
生成对抗网络(GANs)入门介绍指南:让AI学会“创造“的魔法(二)【深入版】
人工智能·pytorch·深度学习·神经网络·算法·生成对抗网络·计算机视觉
qq_5344525219 分钟前
【算法 day02】LeetCode 209.长度最小的子数组 | 59.螺旋矩阵II
java·算法·leetcode·职场和发展
dying_man22 分钟前
LeetCode--31.下一个排列
算法·leetcode
IC 见路不走28 分钟前
LeetCode 第75题:颜色分类
数据结构·算法·leetcode
Navigator_Z41 分钟前
LeetCode //C - 757. Set Intersection Size At Least Two
c语言·算法·leetcode
Blue.ztl2 小时前
DP刷题练习(二)
算法·cpp
青山是哪个青山2 小时前
位运,模拟,分治,BFS,栈和哈希表
算法·散列表·宽度优先
Zephyrtoria4 小时前
区间合并:区间合并问题
java·开发语言·数据结构·算法
柏箱6 小时前
容器里有10升油,现在只有两个分别能装3升和7升油的瓶子,需要将10 升油等分成2 个5 升油。程序输出分油次数最少的详细操作过程。
算法·bfs
Hello eveybody7 小时前
C++介绍整数二分与实数二分
开发语言·数据结构·c++·算法