题目链接: 冗余链接Ⅱ
看了这道题没什么思路,学习了代码随想录 冗余链接Ⅱ 的解题思路。
本体可以描述为有一个有向图,是由一颗有向树 + 一条有向边组成的 (所以此时这个图就不能称之为有向树),现在让我们找到那条边 把这条边删了,让这个图恢复为有向树。将问题拆分为两部分:
- 存在入度为 2 的节点,那么只要从进入这个节点的两条边中选择一条删除即可,删除该边后,整个树仍然需要是连通的
- 不存在入度为 2 的节点,那么整个树在加入一条边后,存在环,找到成环的边,删除即可
#include <bits/stdc++.h>
using namespace std;
int n;
vector<int> father(1001, 0);
void init(int n){
for(int i = 1; i <= n; i++){
father[i] = i;
}
}
int find(int t){
return t == father[t] ? t : father[t] = find(father[t]);
}
bool isSame(int u, int v){
u = find(u);
v = find(v);
return u == v;
}
void join(int u, int v){
u = find(u);
v = find(v);
if(u == v){
return;
}
father[v] = u;
}
bool isTreeAfterRemoveEdge(vector<vector<int>>& edges, vector<int>& removeEdge){
init(n);
for(auto& edge : edges){
if(edge == removeEdge){
continue;
}
if(isSame(edge[0], edge[1])){
return false;
}
join(edge[0], edge[1]);
}
return true;
}
void getRemoveEdge(vector<vector<int>> edges){
init(n);
for (auto& edge : edges) {
if (isSame(edge[0], edge[1])) {
cout << edge[0] << " " << edge[1];
return;
} else {
join(edge[0], edge[1]);
}
}
}
int main(){
int s,t;
cin >> n;
vector<vector<int>> edges;
vector<vector<int>> delEdges;
vector<int> parents(n + 1, 0);
for(int i = 0; i < n; i++){
cin >> s >> t;
edges.push_back({s, t});
parents[t]++;
}
for(int i = edges.size() - 1; i >= 0; i--){
if(parents[edges[i][1]] == 2){
delEdges.push_back(edges[i]);
}
}
if (delEdges.size() > 0) {
if (isTreeAfterRemoveEdge(edges, delEdges[0])) {
cout << delEdges[0][0] << " " << delEdges[0][1];
} else {
cout << delEdges[1][0] << " " << delEdges[1][1];
}
return 0;
}
getRemoveEdge(edges);
return 0;
}