题意
给你一张图,求割点个数。
思路
割点也叫割顶。
①根节点有两个及以上的就是割点。
②如果有一条边u->v,且LOW[v] >= DFN[u],那么u就是割点。
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e5 + 5;
struct Edge
{
int from, to;
Edge (int from, int to): from(from), to(to) {}
};
struct VertexBCC//点双连通
{
//有无重边无影响
int n, m;
int DFN[MAXN], iscut[MAXN], bccno[MAXN], dfs_clock, bcc_cnt;
vector<Edge> edges;
vector<int> G[MAXN], bcc[MAXN];
stack<Edge> S;
void init(int n)
{
this->n = n, m = 0;
edges.clear();
for (int i = 0; i < n; i++) G[i].clear();
}
void AddEdge (int from, int to)
{
edges.push_back(Edge(from, to));
edges.push_back(Edge(to, from));
m = edges.size();
G[from].push_back(m-2);
G[to].push_back(m-1);
}
int dfs(int u, int fa)
{
int lowu = DFN[u] = ++dfs_clock;
int child = 0;
for (int i = 0; i < G[u].size(); i++)
{
Edge e = edges[G[u][i]];
int v = e.to;
if (!DFN[v])//没有访问过v
{
S.push(e);
child++;
int lowv = dfs(v, u);
lowu = min(lowu, lowv); //用后代的low函数更新自己
if (lowv >= DFN[u])
{
iscut[u] = true;
bcc_cnt++; bcc[bcc_cnt].clear(); //注意!bcc从1开始编号
while (1)
{
Edge x = S.top(); S.pop();
if (bccno[x.from] != bcc_cnt)
bcc[bcc_cnt].push_back(x.from), bccno[x.from] = bcc_cnt;
if (bccno[x.to] != bcc_cnt)
bcc[bcc_cnt].push_back(x.to), bccno[x.to] = bcc_cnt;
if (x.from == u && x.to == v) break;
}
}
}
else if (DFN[v] < DFN[u] && v != fa)
{
S.push(e);
lowu = min(lowu, DFN[v]); //用返祖边更新自己
}
}
if (fa < 0 && child == 1) iscut[u] = 0;
return lowu;
}
void find_bcc()
{
//调用结束后s保证为空,所以不用清空
memset(DFN, 0, sizeof(DFN));
memset(iscut, 0, sizeof(iscut));
memset(bccno, 0, sizeof(bccno));
dfs_clock = bcc_cnt = 0;
for (int i = 0; i < n; i++)
if (!DFN[i]) dfs(i, -1);
}
}gao;
int n;
int main()
{
while (~scanf("%d", &n) && n)
{
gao.init(n);
int u, v;
char c;
while (~scanf("%d", &u) && u)
{
u--;
while (~scanf("%d%c", &v, &c))
{
v--;
gao.AddEdge(u , v);
if (c == '\n') break;
}
}
gao.find_bcc();
int ans = 0;
for (int i = 0; i < n; i++)
{
if (gao.iscut[i]) ans++;
}
printf("%d\n", ans);
}
return 0;
}
/*
5
5 1 2 3 4
0
6
2 1 3
5 4 6 2
0
0
*/