当前位置: 代码迷 >> 综合 >> [hihoCoder 1190] 连通性·四:点-双连通分量
  详细解决方案

[hihoCoder 1190] 连通性·四:点-双连通分量

热度:73   发布时间:2024-01-05 02:21:51.0

题意:求点-双连通分量,输出每条边所在双连通分量中边的最小编号。

先前AC了,修改了一个地方,WA。本地对拍,段错误。以为是dfs爆栈,结果是数组越界……那之前是怎么AC的呢?修正了数组的越界,就AC了。

验证了我的理解:pre[v] < pre[u]用来确保反向边只在第一次访问时入栈,换成判断bccno[i->id]是否为0效果是相同的。

#include <cstdio>
#include <vector>
#include <stack>
#include <algorithm>
const int MAX_N = 20000, MAX_M = 100000;
using namespace std;
struct Edge {int v, id;
};
typedef vector<Edge>::iterator iter;
vector<Edge> E[MAX_N+1];
stack<Edge> S;
int dfs_clock, bcc_cnt, pre[MAX_N+1], low[MAX_N+1], bccno[MAX_M+1], r[MAX_M+1];void tarjan(int u, int fa)
{low[u] = pre[u] = ++dfs_clock;for (iter i = E[u].begin(); i != E[u].end(); ++i) {int v = i->v;if (!pre[v]) {S.push(*i);tarjan(v, u);if (low[v] >= pre[u]) {Edge e;++bcc_cnt;do {e = S.top();S.pop();bccno[e.id] = bcc_cnt;} while (e.id != i->id);} elselow[u] = min(low[u], low[v]);} else if (pre[v] < pre[u] && v != fa) { // 反向边S.push(*i);low[u] = min(low[u], pre[v]);}}
}int main()
{int n, m;scanf("%d %d", &n, &m);for (int i = 1; i <= m; ++i) {int u, v;scanf("%d %d", &u, &v);E[u].push_back((Edge){v, i});E[v].push_back((Edge){u, i});r[i] = m;}for (int i = 1; i <= n; ++i)if (!pre[i])tarjan(i, 0);for (int i = 1; i <= m; ++i)r[bccno[i]] = min(r[bccno[i]], i);printf("%d\n", bcc_cnt);for (int i = 1; i <= m; ++i)printf("%d%c", r[bccno[i]], " \n"[i==m]);return 0;
}
  相关解决方案