题目要求:在连通无向图中找一个奇环(顶点数为奇数)。
关键定理:
无向图存在奇环 ⇔ 该图不是二分图(不能二染色)。
所以解法分为两步:
- 二分图染色(BFS)——尝试给每个顶点标上 0/1 两种颜色,使每条边两端颜色不同。
- 如果染色过程出现冲突(一条边两端颜色相同),说明不是二分图,一定存在奇环。利用这条冲突边和 BFS 树构造出具体的奇环。
怎么构造呢
假设冲突边为 (u, v),且 color[u] == color[v]。
我们要利用 BFS 树 和这条非树边(冲突边)构造出一个环。
环的路线:从 u 向上走到 LCA(最近公共祖先),再向下走到 v,最后通过冲突边 v — u 闭合。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
| #include <bits/stdc++.h> using namespace std; #define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0) #define endl "\n" #define int long long #define ld long double const int mod1 = 1e9 + 7; const int mod2 = 998244353; const double PI = acos(-1.0),eps=1e-12L; const long long inf=1e18+10; const int mod=mod1; void solve(){ int n,m; cin>>n>>m; vector<int> edge[n+1]; for (int i=0;i<m;i++){ int u,v; cin>>u>>v; edge[u].push_back(v); edge[v].push_back(u); } vector<int> col(n+1,-1),p(n+1),dis(n+1); bool found=0; vector<int> cycle; queue<int> q; col[1]=0; q.push(1); while (!q.empty() && !found){ int u=q.front(); q.pop(); for (int v:edge[u]){ if (col[v]==-1){ col[v]=col[u]^1; dis[v]=dis[u]+1; p[v]=u; q.push(v); }else if (col[u]==col[v]){ found=1; int a=u,b=v; while (dis[a]>dis[b]) a=p[a]; while (dis[b]>dis[a]) b=p[b]; while (a!=b){ a=p[a]; b=p[b]; } int lca=a; vector<int> path1; int cur=u; while (cur!=lca){ path1.push_back(cur); cur=p[cur]; } path1.push_back(lca); cur=v; vector<int> path2; while (cur!=lca){ path2.push_back(cur); cur=p[cur]; } cycle=path1; for (int i=path2.size()-1;i>=0;i--) cycle.push_back(path2[i]); break; } } } if (!found){ cout<<-1<<endl; }else{ cout<<cycle.size()<<endl; for (int v:cycle){ cout<<v<<' '; } cout<<endl; } } signed main(){ IOS; int T=1; cin>>T; while (T--) solve(); return 0; }
|