http://acm.hust.edu.cn/vjudge/contest/view.action?cid=82833#problem/B
UVA链接地址 https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=251
题目大意:
给你一个无向图,求其中割点的个数目。
输入数据
第一行一个 n 代表有 n 个点
接下来有多行,一直到读入一个 0,算整个地图的读入结束,再读入一个0,文件数据结束。
每行有第一个数字a,代表接下来的数字都 和 a 相连。
知识汇总:
割点:无向连通图中,如果删除某点后,图变成不连通了,则称该点为割点。
这里割点 和 桥 都是无向图里的概念,大家在这里不要混淆了。
求割点
一个顶点u是割点,当且仅当满足(1)或(2)
(1) u为树根,且u有多于一个子树。
(2) u不为树根,且满足存在(u,v)为树枝边(或称 父子边,即u为v在搜索树中的父亲),使得 dfn(u)<=low(v)。(也就是说 V 没办法绕过 u 点到达比 u dfn要小的点)
注:这里所说的树是指,DFS下的搜索树。
求割点 tarjan里 low 和 dfn
dfn[u]定义和前面类似,但是low[u]定义为u
或者u的子树中能够通过非父子边追溯到的
最早的节点的DFS开始时间
在Tarjan算法求割点我们要加一个数组 Father[u], 判断两者是否是父子边
///#pragma comment (linker, "/STACK:102400000,102400000")
#include <iostream>
#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <limits>
#include <stack>
#include <vector>
#include <map>
using namespace std;
#define N 3010
#define INF 0xfffffff
#define PI acos (-1.0)
#define EPS 1e-8
#define met(a, b) memset (a, b, sizeof (a))
vector <vector <int> > G;
int n, Time, vis[N], low[N], dfn[N], f[N];
void Init ();
int solve ();
void Tarjan (int u, int fa);
int main ()
{
while (scanf ("%d", &n), n)
{
Init ();
int a, b;
char ch;
while (scanf ("%d", &a), a)
{
while (scanf ("%d%c", &b, &ch))
{
G[a].push_back (b);
G[b].push_back (a);
if (ch == '\n') break;
}
}
printf ("%d\n", solve ());
}
return 0;
}
void Init ()
{
G.clear ();
G.resize (n+1);
met (low, 0);
met (dfn, 0);
Time = 0;
}
int solve ()
{
int ans = 0, rt = 0;
met (vis, 0);
Tarjan (1, 0);
for (int i=2; i<=n; i++)
{
int v = f[i];
if (v == 1) rt++;
if (dfn[v] <= low[i]) vis[v] = 1;
}
for (int i=2; i<=n; i++)
if (vis[i]) ans++;
if (rt > 1) ans++;
return ans;
}
void Tarjan (int u, int fa)
{
low[u] = dfn[u] = ++Time;
f[u] = fa;
int len = G[u].size (), v;
for (int i=0; i<len; i++)
{
v = G[u][i];
if (!dfn[v])
{
Tarjan (v, u);
low[u] = min (low[u], low[v]);
}
else if (v != fa)
low[u] = min (low[u], dfn[v]);
}
}