判环的几种方法
拓扑排序判环
- 对于有向图:
//有向图环判断 #include<bits/stdc++.h> using namespace std; vector<int>edge[10001]; int n,m,d[10001]; queue<int>q; inline void TopoSort() { int cnt = 0; for(int i = 1;i<=n;i++) { if(!d[i]) { q.push(i); ++cnt; } } while(!q.empty()) { int x = q.front(); q.pop(); for(auto y:edge[x]) if(--d[y]==0) { q.push(y); ++cnt; } } if(cnt==n)cout<<"No\n"; else cout<<"Yes\n"; } int main() { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); cin>>n>>m; for(int i =1 ;i<=m;i++) { int x,y; cin>>x>>y; edge[x].push_back(y); ++d[y]; } TopoSort(); return 0; } /* 4 4 1 2 2 3 3 4 1 4 No */
- 对于无向图
因为是双向边,那么我们需要先把度数为
for(int i = 1; i <= n; i++) if(d[i] == 1) q.push(i),vis2[i] = true;
然后当]之前没有访问过且减去和上一个点所连的边带来的影响之后度数是不是小于等于1,是的话加入队列里面。
while(!q.empty()) { int u = q.front(); q.pop(); for(auto v : e[u]) if(--d[v] <= 1 && !vis2[v]) q.push(v),vis2[v] = true; }
最后度数大于
板子:
// AC one more times // nndbk #include <bits/stdc++.h> using namespace std; typedef long long ll; const int mod = 1e9 + 7; const int N = 2e5 + 10; int n,d[N]; vector<int> e[N]; bool vis[N]; void toposort() { queue<int> q; for(int i = 1;i <= n; i++) vis[i] = 0; for(int i = 1; i <= n; i++) if(d[i] == 1) q.push(i),vis[i] = true; while(!q.empty()) { int u = q.front(); q.pop(); for(auto v : e[u]) if(--d[v] <= 1 && !vis[v]) q.push(v),vis[v] = true; } } int main() { ios::sync_with_stdio(false); cin.tie(nullptr), cout.tie(nullptr); cin>>n; for(int i = 1; i <= n; i++) { int u , v; cin>>u>>v; e[u].push_back(v); e[v].push_back(u); d[u]++; d[v]++; } toposort(); set<int>s; for(int i = 1;i <= n; i++) if(d[i]>1)s.insert(i); for(auto x : s) cout<<x<<" "; cout<<"\n"; return 0; }
例题:H. Mad City
// AC one more times // nndbk #include <bits/stdc++.h> using namespace std; typedef long long ll; const int mod = 1e9 + 7; const int N = 2e5 + 10; int n,a,b,d[N]; bool vis[N]; ll dist1[N],dist2[N]; vector<int> e[N]; bool vis2[N]; int tot,l[N]; void toposort() { queue<int> q; tot = 0; for(int i = 1;i <= n; i++) vis2[i] = 0; for(int i = 1; i <= n; i++) if(d[i] == 1) q.push(i),vis2[i] = true; while(!q.empty()) { int u = q.front(); q.pop(); //l[++tot] = u; // cout<<"u = "<<u<<"\n"; for(auto v : e[u]) if(--d[v] <= 1 && !vis2[v]) q.push(v),vis2[v] = true; } // for(int i = 1;i <= tot; i++) // cout<<l[i]<<" "; // cout<<"\n"; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr), cout.tie(nullptr); int t; cin>>t; while(t--) { cin>>n>>a>>b; for(int i = 1;i <= n; i++) e[i].clear(),dist1[i] = 0,dist2[i] = 0,d[i] = 0; for(int i = 1; i <= n; i++) { int x , y; cin>>x>>y; e[x].push_back(y); e[y].push_back(x); d[y]++; d[x]++; } toposort(); queue<pair<int,ll>>q; q.push({a,0}); dist1[a] = 0; memset(vis,false,sizeof(vis)); vis[a] = true; while(!q.empty()) { auto i = q.front(); q.pop(); int u = i.first,dis = i.second; for(auto v : e[u]) { if(!vis[v]) { vis[v] = true; dist1[v] = dis + 1; q.push({v,dist1[v]}); } } } q.push({b,0}); dist2[b] = 0; memset(vis,false,sizeof(vis)); vis[b] = true; while(!q.empty()) { auto i = q.front(); q.pop(); int u = i.first,dis = i.second; for(auto v : e[u]) { if(!vis[v]) { vis[v] = true; dist2[v] = dis + 1; q.push({v,dist2[v]}); } } } bool ok = false; // for(int i = 1;i <= n;i++) // cout<<d[i]<<" "; // cout<<"\n"; // for(int i = 1;i <= n;i++) // cout<<dist1[i]<<" "; // cout<<"\n"; // for(int i = 1;i <= n;i++) // cout<<dist2[i]<<" "; // cout<<"\n"; for(int i = 1;i <= n;i++) { if(d[i]>1&&dist1[i]>dist2[i])ok = true; } if(ok)cout<<"YES\n"; else cout<<"NO\n"; } return 0; }
dfs判环
如果一个状态为
// AC one more times // nndbk #include <bits/stdc++.h> using namespace std; const int N = 1e5 + 10; vector <int> e[N]; int vis[N]; int n, m; bool dfs(int u) { vis[u] = 1; // 1表示正在访问 for (int v: e[u]) { if (vis[v] == 1) { //如果正在访问的点又被访问到则代表有环 return false; } else if (vis[v] == 0) { // 0代表还没有访问 if (!dfs(v)) { return false; } } } vis[u] = 2; // 2代表访问结束 return true; } bool check(){ for (int i = 1; i <= n; i++) { if (vis[i] == 0) { if (!dfs(i)) { return false; } } } return true; }; int main() { cin >> n >> m; for (int i = 0; i < m; i++) { int u,v; cin >> u >> v; e[u].push_back(u); } memset(vis, 0, sizeof(vis)); puts(check() ? "no have" : "have"); return 0; }
dfs找环数和找路径
#include<bits/stdc++.h> using namespace std; const int N = 1e6; int nums = 0; int vis[N],pre[N]; vector<int>e[N]; void dfs(int u,int fa){ //dfs vis[u] = 1; for(auto v : e[u]){ if(v==fa) continue; //如果是无向的 a-->b 的同时也有 b-->a,所以直接排除另外的一种情况 if(vis[v]==0){ //如果没有访问就标记当前元素的前一个元素 pre[v] = u; dfs(v,u); //并且一直递归访问下去 }else if(vis[v]==1){ int tmp = u,cnt = 1;//环的长度 while(tmp != v) { cout<<tmp<<" "; cnt++; tmp = pre[tmp]; } cout<<v<<"\n"; nums++; } } vis[u] = 2; } int main() { int n;int u,v; //n为点数 m为边数 u是起点v是终点 cin >> n; for(int i = 1;i <= n;i++){ cin >> u >> v; e[u].push_back(v); e[v].push_back(u); } for(int i = 1;i <= n;i++){ //可能是非联通图 if(vis[i]==0) //每一次可以访问完和该点相连的所有点 dfs(i,-1); } cout << nums << endl; //环数 return 0; } /* 3 3 2 1 3 2 1 3 */
分类:
图论
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix