洛谷: P1656 炸铁路(并查集)

今天记录一道并查集的题目。

思路: 枚举每一条铁路,假设去掉这条铁路,检测图中的n个地点是否还能连通。如果不能连通,说明需要炸掉这条路,如果能连通,说明去掉这条路并不影响连通性,就没必要把这条路炸了。

注意Union方法,如果x和y的根节点是一样的,直接return,否则就成环了。

注:vector中pair的默认排序是第一个从小往大排,第一个一样的情况下按照第二个排。所以就用的vector的pair,没用结构体。(因为我对C++不太熟悉,所以就注明一下这个问题)

代码:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 155;
const int maxm = 5005;
int ranks[maxn], parent[maxn], n, m;
vector<pair<int, int>> edges;
void init() {
	for (int i = 1; i <= n; i++) {
		parent[i] = -1;
		ranks[i] = 0;//高度
	}
}
int find(int x) {
	int x_root = x;
	while (parent[x_root] != -1)
		x_root = parent[x_root];
	return x_root;
}
void Union(int x,int y) {
	int x_root = find(x);
	int y_root = find(y);
	if (x_root == y_root) return;
	if (ranks[x_root] < ranks[y_root]) {
		parent[x_root] = y_root;
	}
	else if (ranks[x_root] > ranks[y_root]) {
		parent[y_root] = x_root;
	}
	else {
		parent[x_root] = y_root;
		ranks[y_root]++;
	}
}
int main() {
	cin >> n >> m;//m个铁路
	edges.resize(m + 1);
	for (int i = 0; i < m; i++) {
		cin >> edges[i].first >> edges[i].second;
		if (edges[i].first > edges[i].second) swap(edges[i].first, edges[i].second);
	}
	sort(edges.begin(), edges.begin()+m);
	//枚举去掉某条道路 将剩下的合并
	for (int i = 0; i < m; i++) {
		init();
		for (int j = 0; j < m; j++) {//合并剩下的
			if (j != i) {
				Union(edges[j].first, edges[j].second);
			}
		}
		//检测有几个祖先
		bool flag = true;
		int par = find(1);//结点1
		for (int j = 2; j <= n; j++) {
			if (find(j) != par) {
				flag = false;
				break;
			}
		}
		if (!flag) {
			cout << edges[i].first << " " << edges[i].second << endl;
		}
	}
	return 0;
}

posted @ 2024-03-04 20:17  YuKiCheng  阅读(70)  评论(0编辑  收藏  举报  来源