题意
传送门 LeeCode 685
题解
此时图中一定出现环。
考虑所有节点度都小于等于 的情况,此时环首尾相连,环上任意边均为可能答案,取索引值最大的即可;用并查集合并节点,第一次出现两端节点连通的边即答案。
考虑存在度为 的结点的情况,此时答案为指向该节点的边之一;枚举删边,从根节点 dfs 即可,若不能遍历全部节点,则当前删除边非答案;若 条边枚举删除后 dfs 都满足条件,取索引值最大的即可。
const int MAX_N = 1e3 + 1;
class Solution {
private:
// 并查集模板
int par[MAX_N];
int rank[MAX_N];
void union_find_init(int n){
for(int i = 0; i < n; i++){
par[i] = i;
rank[i] = 0;
}
}
int find(int x){
if(par[x] == x) return x;
return par[x] = find(par[x]);
}
bool same(int x, int y){
return find(x) == find(y);
}
void unite(int x, int y){
x = find(x), y = find(y);
if(x == y) return;
if(rank[x] > rank[y]) par[y] = x;
else{
if(rank[x] == rank[y]) ++rank[y];
par[x] = y;
}
}
vector<int> G[MAX_N]; // 有向图
bool used[MAX_N]; // dfs 标记
int cnt; // 连通节点数
void dfs(int u){
used[u] = true;
++cnt;
for(int i = 0; i < G[u].size(); i++){
int v = G[u][i];
if(!used[v]) dfs(v);
}
}
void init_dfs(int v, int e, int del, vector<vector<int>>& edges){
memset(used, 0, sizeof(used));
cnt = 0;
for(int i = 1; i <= v; i++) G[i].clear();
for(int j = 0; j < e; j++){
if(j != del) G[edges[j][0]].push_back(edges[j][1]);
}
}
public:
vector<int> findRedundantDirectedConnection(vector<vector<int>>& edges) {
vector<int> res(2);
int sz = edges.size();
vector<int> d(sz + 1), pre(sz + 1);
int e = -1;
for(int i = 0; i < sz; i++){
int u = edges[i][0], v = edges[i][1];
if(++d[v] == 2){
e = i;
}
else pre[v] = i;
}
// 处理出现度为 2 的节点的情况
if(e != -1){
int s;
for(int i = 1; i <= sz; i++) {
if(d[i] == 0){
s = i;
break;
}
}
int e2 = pre[edges[e][1]];
init_dfs(sz, sz, e, edges);
dfs(s);
if(cnt < sz) res = edges[e2];
else{
init_dfs(sz, sz, e2, edges);
dfs(s);
if(cnt < sz) res = edges[e];
else res = e > e2 ? edges[e] : edges[e2];
}
return res;
}
// 所有节点度小于等于 1, 并查集处理即可
union_find_init(sz);
for(int i = 0; i < sz; i++){
int u = edges[i][0], v = edges[i][1];
if(!same(u, v)){
unite(u, v);
}
else{
res = edges[i];
break;
}
}
return res;
}
};