题目
思路
链式前向星
一种图的存储方式。不懂可以看一下董晓算法。使用这种存储方式是为了方便寻找反向边。
Tarjan
通过dfs,记录时间戳。
差分区间
不记录最早能到达的节点而是用差分,减少比较的次数。
题解
class Solution {
// 环边依然会重复遍历
private:
const static int N = 100010, M = 200010;
vector<vector<int>> edge;
int index = 0;
int c = 0;
int nxt[M];
int h[N];
int first[N];
int second[N];
int to[M]{0};
bool pair_visited[M]{0};
int low[N]{0};
int dfn[N]{0};
int k = -1;
int st = -1;
public:
inline void add(int a, int b) {
nxt[index] = h[a];
h[a] = index;
to[index] = b;
++index;
}
vector<vector<int>> criticalConnections(int n,
vector<vector<int>>& connections) {
int m = connections.size();
std::fill_n(h, n, -1);
while (++k < m) {
int u = connections[k][0], v = connections[k][1];
add(u, v);
add(v, u);
}
int p;
first[++st] = 0;
dfn[st] = ++c;
second[st] = -1;
while (true) {
next:
int cur = first[st];
int l = h[cur];
while (~l) {
int j = to[l];
if (pair_visited[l ^ 1] | pair_visited[l]) {
// 异或的方法,
l = nxt[l];
continue;
}
else
pair_visited[l] = 1;
l = nxt[l];
if (!dfn[j]) {
dfn[j] = ++c;
first[++st] = j;
second[st] = cur;
goto next;
// goto效率
}
++low[cur];
--low[j];
}
p = second[st];
if (!~p)
return edge;
if (low[cur]) {
low[p] += low[cur];
} else {
edge.push_back({cur, p});
}
--st;
}
}
};