思路:
\qquad
根据题意,题目中的有向图为一棵树加上一条冗余边。一棵树的所有子节点入度均为1,根节点入度为0,因此可以分为以下两种情况:
\qquad
(1)图中存在入度为2的节点。因为根节点的入度为0,添加一条边,入度最多加1,因此入度为2的点一定是子节点,要删除的边一定是连向这个节点的边之一,根是入度为0的节点。此时考虑删掉每条连向该节点的边,对剩下的图从根节点拓扑排序,若没有环且能遍历到所有点,则枚举的边就是答案;
\qquad
(2)图中点的入度均为1,即从子节点向根节点连一条边。此时按照边的顺序,遍历所有边,每次将一条边连接的两点合并到一个联通块。当遇到一条边的两点属于同一个联通块时,即为答案。
代码:
class Solution {
public:
vector<int> findRedundantDirectedConnection(vector<vector<int>>& edges) {
for(int i = 0;i < 1005; ++i) p[i] = i, in[i] = 0;
vector<int> ans;
ans.push_back(0), ans.push_back(0);
int pos_0 = 0;
int pos_2 = 0;
for(int i = 0;i < edges.size(); ++i)
{
int u = edges[i][0];
int v = edges[i][1];
in[v]++;
E[u].push_back(v);
if(in[v] == 2) pos_2 = v;
}
for(int i = 1;i <= edges.size(); ++i) if(in[i] == 0) pos_0 = i;
if(in[pos_2] == 2)
{
for(int i = 0;i < edges.size(); ++i)
{
int u = edges[i][0];
int v = edges[i][1];
if(v == pos_2)
{
del_u = u;
del_v = v;
sum = 1;
memset(r, false, sizeof(r));
r[pos_0] = true;
if(topology(pos_0) && sum == edges.size())
{
ans[0] = u;
ans[1] = v;
}
}
}
}
else
{
for(int i = 0;i < edges.size(); ++i)
{
int u = edges[i][0];
int v = edges[i][1];
int u_p = find(u);
int v_p = find(v);
if(u_p < v_p) p[v] = u_p;
else if(u_p > v_p) p[u] = v_p;
else
{
ans[0] = u;
ans[1] = v;
break;
}
}
}
return ans;
}
int p[1005];
int in[1005];
bool r[1005];
int del_u;
int del_v;
int sum = 1;
vector<int> E[1005];
int find(int x)
{
return x == p[x] ? x : p[x] = find(p[x]);
}
bool topology(int u)
{
for(int i = 0;i < E[u].size(); ++i)
{
int v = E[u][i];
if(u == del_u && v == del_v) continue;
if(r[v]) return false;
++sum;
r[v] = true;
topology(v);
}
return true;
}
};