赞
踩
用一个数组记录每个节点的父节点,这个父节点是可以变化的,在加入新的边的过程中,我们可以不断更新这个数组使其指向一个最远的节点,遇到并不指向一处的新节点,则将这个最远的节点指向新节点;
如果两个节点都是新节点,则将前面一个节点的父节点设置为后一个节点
模板代码如下:
int father[101]; void init() { for (int i = 0; i <= 100; i++) father[i] = i; } int find(int a) { while (father[a] != a) { a = father[a]; } return a; } bool isSame(int a, int b) { a = find(a); b = find(b); return a == b; } void join(int a, int b) { if (isSame(a, b)) return; father[find(a)] = b; return; }
这是一个无向图找路径的问题,之前我们已经用深搜的方法将路径打印出来了,但这题只需要找是否存在路径,那么就可以用并查集判断连通性来节省时间了
#include <iostream> using namespace std; int father[101]; void init() { for (int i = 0; i <= 100; i++) father[i] = i; } int find(int a) { while (father[a] != a) { a = father[a]; } return a; } bool isSame(int a, int b) { a = find(a); b = find(b); return a == b; } void join(int a, int b) { if (isSame(a, b)) return; father[find(a)] = b; return; } int main() { int m, n; cin >> n >> m; int s, t; init(); for (int i = 0; i < m; i++) { cin >> s >> t; join(s, t); } int source, destination; cin >> source >> destination; if (isSame(source, destination)) cout << 1 << endl; else cout << 0 << endl; return 0; }
其实本质上是要从环中删除一条边,如果遇到两个已经连同的节点又在一条新输入的边中出现时,即可打印输出了。和题目要求中输出最后一条可删除的边的要求并不冲突
#include <iostream> using namespace std; int father[1001]; void init() { for (int i = 0; i <= 1000; i++) father[i] = i; } int find(int a) { while (father[a] != a) { a = father[a]; } return a; } bool isSame(int a, int b) { a = find(a); b = find(b); return a == b; } void join(int a, int b) { if (isSame(a, b)) return; father[find(a)] = b; return; } int main() { int n; cin >> n; int s, t; init(); for (int i = 0; i < n; i++) { cin >> s >> t; if (isSame(s, t)) { cout << s << ' ' << t << endl; return 0; } join(s, t); } return 0; }
这题加上了对于节点入度的判断,入度为2的节点需要着重处理,如果删除后其余节点仍旧能够构成有向环,说明删除的边是必不可少的边,而留下的才是构成了有向环的那一条边
而如果没有入度为2的节点,直接按照上一题的删除思路来就行了
#include <iostream> #include <vector> using namespace std; int father[1001]; void init() { for (int i = 0; i <= 1000; i++) father[i] = i; } int find(int a) { while (father[a] != a) { a = father[a]; } return a; } bool isSame(int a, int b) { a = find(a); b = find(b); return a == b; } void join(int a, int b) { if (isSame(a, b)) return; father[find(a)] = b; return; } void getRemovedEdge(vector<vector<int>>& edge) { init(); for (int i = 0; i < edge.size(); i++) { if (isSame(edge[i][0], edge[i][1])) { cout << edge[i][0] << ' ' << edge[i][1] << endl; return; } else { join(edge[i][0], edge[i][1]); } } } int isTreeAfterRemoveEdge(const vector<vector<int>>& edge, int deleteEdge) { init(); // 初始化并查集 for (int i = 0; i < edge.size(); i++) { if (i == deleteEdge) continue; if (isSame(edge[i][0], edge[i][1])) { // 构成有向环了,一定不是树 return false; } join(edge[i][0], edge[i][1]); } return true; } int main() { int n; cin >> n; int s, t; vector<vector<int>> edge; vector<int> inDegree(n+1, 0); for (int i = 0; i < n; i++) { cin >> s >> t; inDegree[t]++; edge.push_back({s, t}); } vector<int> vec; for (int i = n-1; i >= 0; i--) { if (inDegree[edge[i][1]] == 2) { vec.push_back(i); } } if (vec.size() > 0) { if (isTreeAfterRemoveEdge(edge, vec[0])) { cout << edge[vec[0]][0] << ' ' << edge[vec[0]][1] << endl; } else { cout << edge[vec[1]][0] << ' ' << edge[vec[1]][1] << endl; } } else getRemovedEdge(edge); return 0; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。