强连通缩点,统计入度为1的缩点后的点的个数
个数1的话输出这个强连通分量的点的数量
否则输出0;
code
/* Kosaraju算法,无向图的强连通分量,时间复杂度O(n+m) 思路: 按照图G的深度遍历序列,在G的反图上进行深搜 能够搜到的点集就是一个强联通分量 */ #include <iostream> #include <cstring> using namespace std; const int INF = 10009; //链接表,偶数边为原图,奇数边为反图 struct node { int v, ne; } edge[100009]; /* scc是强连通子图的个数 dfn为深度遍历序列(逆序即反图的拓扑排序) vis为访问标记,sum记录每个强连通分量的节点数 */ int head[INF], dfn[INF], vis[INF], sum[INF], n, m, scc, cnt = 1, tol; void adde (int u, int v) { edge[++cnt].v = v; edge[cnt].ne = head[u]; head[u] = cnt; } void dfs (int k) { vis[k] = 1; for (int i = head[k]; i != 0; i = edge[i].ne) if ( (i & 1) == 0 && !vis[edge[i].v]) dfs (edge[i].v); dfn[++tol] = k; } void ndfs (int k) { vis[k] = scc, sum[scc]++; for (int i = head[k]; i != 0; i = edge[i].ne) if ( (i & 1) && !vis[edge[i].v]) ndfs (edge[i].v); } void Kosaraju() { for (int i = 1; i <= n; i++) if (!vis[i]) dfs (i); memset (vis, 0, sizeof vis); for (int i = n; i > 0; i--) if (!vis[dfn[i]]) scc++, ndfs (dfn[i]); } int make() { int deg[INF] = {0}; //由反图统计每个强联通点的有无出度 for (int i = 3; i <= cnt; i += 2) { if (vis[edge[i].v] == vis[edge[i ^ 1].v]) continue; deg[vis[edge[i].v]]++; } int j, t = 0; for (int i = 1; i <= scc; i++) if (deg[i] == 0) j = i, t++; if (t == 1) return sum[j]; return 0; } int main() { int x, y; cin >> n >> m; for (int i = 1; i <= m; i++) { cin >> x >> y; adde (x, y), adde (y, x); } Kosaraju(); cout << make(); return 0; }
时间: 2024-10-21 06:37:12