b_lc_发现环(并查集+dfs / 拓扑排序)
小明的实验室有N台电脑,编号1~N。原本这N台电脑之间有N-1条数据链接相连,恰好构成一个树形网络。网络中出现了环路。
从小到大的顺序输出在环路上的电脑的编号(N<=100000)
方法一:并查集+dfs
思路
这题不用并查集找环的起点的话需要 O(n) 时间确定找,会t,这里用了并查集优化找环过程
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5;
int n,m,st,ed,found,fa[N],vis[N];
vector<int> path, g[N];
int find(int u) {return fa[u]==u ? u : fa[u]=find(fa[u]);}
void merge(int a, int b) {
fa[find(a)]=find(b);
}
void dfs(int u) {
if (found) return;
path.push_back(u);
if (u==ed) {
sort(path.begin(), path.end());
for (int v : path) cout<<v<<' ';
found=1;
return;
}
for (int v : g[u]) if (!vis[v]) {
vis[v]=1;
dfs(v);
vis[v]=0;
}
path.pop_back();
}
int main() {
std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
cin>>n; for (int i=1; i<=n; i++) fa[i]=i;
for (int i=0; i<n; i++) {
int a,b; cin>>a>>b;
g[a].push_back(b), g[b].push_back(a);
if (find(a)!=find(b)) merge(a,b);
else st=a,ed=b;
}
dfs(st);
return 0;
}
方法二:拓扑排序
思路
从入度为 1 的结点开始拓扑排序,遍历到的点入度都减 1,剩下的入度为 2 的结点都是遍历不到的,也就是环上的结点(环上只有一个结点的入度 ≥ 2)
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+50;
int n, s, e, vis[N], fa[N], in[N];
vector<vector<int>> g;
vector<int> bfs() {
queue<int> q;
for (int i=1; i<=n; i++) if (in[i]==1) q.push(i);
while (!q.empty()) {
int u=q.front(); q.pop();
for (int v : g[u]) if (--in[v]==1) {
q.push(v);
}
}
vector<int> ans;
for (int i=1; i<=n; i++) if (in[i]==2) ans.emplace_back(i);
sort(ans.begin(), ans.end());
return ans;
}
int main() {
std::ios::sync_with_stdio(false);
cin >> n;
g.resize(n+1);
for (int i=0; i<n; i++) {
int a, b; cin >> a >> b;
g[a].emplace_back(b), g[b].emplace_back(a);
in[a]++, in[b]++;
}
vector<int> ans=bfs();
for (int i=0; i<ans.size(); i++) cout << ans[i] << ' ';
return 0;
}
复杂度分析
- Time:O(n),
- Space:O(n),