1 条题解
-
0
自动搬运
来自洛谷,原作者为

rainygame
There is no trap so deadly as the trap you set for yourself.搬运于
2025-08-24 22:39:02,当前版本为作者最后更新于2023-06-15 21:39:35,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
前言
作为一个连链式前向星都不会写的蒟蒻,我决定写一篇 vector 存图的题解,以造福后人。
前置学习内容:强连通分量。
定义
- 连通图:任意两个结点都可以相互到达的无向图。
- 桥:一张连通图中,如果删去任意一条边会导致图不连通,则这条边就称为桥。
- 边双连通图:一个没有桥的连通图。
- 边双连通分量:极大的边双连通子图。
算法过程
这个边双连通分量和强连通分量十分类似,强连通分量其实就是把环缩起来,而边双连通分量也是一个环。(因为在环上,就算删去一条边,也一定还有另一条边可以连接)
求强连通分量的代码如下:
int cnt, ssum; int dfn[MAXN], low[MAXN], scc[MAXN]; vector<int> e[MAXN]; bitset<MAXN> ins; stack<int> st; void tarjan(int x){ low[x] = dfn[x] = ++cnt; st.push(x); ins.set(x); for (auto i: e[x]){ if (!dfn[i]){ tarjan(i); low[x] = min(low[x], low[i]); }else if (ins.test(i)){ low[x] = min(low[x], dfn[i]); } } if (dfn[x] == low[x]){ scc[x] = ++ssum; while (st.top() != x){ scc[st.top()] = ssum; ins.reset(st.top()); st.pop(); } st.pop(); ins.reset(x); } }而边双连通分量其实更加简单,因为是无向图,所以不需要考虑横叉边,因此不需要
ins来判断是否在栈中,而是直接else。然后,无向图的边我们一般看成是两条有向图的边,但是这样就会导致一个问题,就是这样会被看成是一个环。所以我们需要加一个判断:不能访问上一个被访问过的结点。
然后答案可以用一个二维 vector 存起来。
给个代码:
int cnt; int dfn[MAXN], low[MAXN]; set<int> e[MAXN]; vector<vector<int>> ans; stack<int> st; void tarjan(int x, int las){ low[x] = dfn[x] = ++cnt; st.push(x); for (auto i: e[x]){ if (i == las) continue; if (!dfn[i]){ tarjan(i, x); low[x] = min(low[x], low[i]); }else low[x] = min(low[x], dfn[i]); } if (dfn[x] == low[x]){ vector<int> vec; vec.push_back(x); while (st.top() != x){ vec.push_back(st.top()); st.pop(); } st.pop(); ans.push_back(vec); } }可是这个代码只能拿到 分:评测记录。为什么呢?
通过下载数据可以发现,数据是有重边的,而重边就可以往回走了。但是我们这个判断就直接把这个机会给“杀死”了。
因此,我们不能根据顶点来判断,而是要根据边来判断,条件是不能走上一次走过的边。我们为了判边,就需要给 vector 多绑上一个
int保存边的编号以判断。这样就可以 AC 本题了!代码如下:
#include <bits/stdc++.h> using namespace std; #define MAXN 500001 int n, m, u, v, cnt; int dfn[MAXN], low[MAXN]; vector<pair<int, int>> e[MAXN]; vector<vector<int>> ans; stack<int> st; void tarjan(int x, int las){ low[x] = dfn[x] = ++cnt; st.push(x); for (auto i: e[x]){ if (i.second == (las ^ 1)) continue; if (!dfn[i.first]){ tarjan(i.first, i.second); low[x] = min(low[x], low[i.first]); }else low[x] = min(low[x], dfn[i.first]); } if (dfn[x] == low[x]){ vector<int> vec; vec.push_back(x); while (st.top() != x){ vec.push_back(st.top()); st.pop(); } st.pop(); ans.push_back(vec); } } int main(){ ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); cin >> n >> m; for (int i(1); i<=m; ++i){ cin >> u >> v; e[u].push_back(make_pair(v, i<<1)); e[v].push_back(make_pair(u, i<<1|1)); } for (int i(1); i<=n; ++i){ if (!dfn[i]) tarjan(i, 0); } cout << ans.size() << '\n'; for (auto i: ans){ cout << i.size() << ' '; for (auto j: i) cout << j << ' '; cout << '\n'; } return 0; }
- 1
信息
- ID
- 7802
- 时间
- 2000~5000ms
- 内存
- 512MiB
- 难度
- 4
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者