Describle
A Telephone Line Company (TLC) is establishing a new telephone cable
network. They are connecting several places numbered by integers from
1 to N. No two places have the same number. The lines are
bidirectional and always connect together two places and in each place
the lines end in a telephone exchange. There is one telephone exchange
in each place. From each place it is possible to reach through lines
every other place, however it need not be a direct connection, it can
go through several exchanges. From time to time the power supply fails
at a place and then the exchange does not operate. The officials from
TLC realized that in such a case it can happen that besides the fact
that the place with the failure is unreachable, this can also cause
that some other places cannot connect to each other. In such a case we
will say the place (where the failure occured) is critical. Now the
officials are trying to write a program for finding the number of all
such critical places. Help them.
Input
The input file consists of several blocks of lines. Each block
describes one network. In the first line of each block there is the
number of places N < 100. Each of the next at most N lines contains
the number of a place followed by the numbers of some places to which
there is a direct line from this place. These at most N lines
completely describe the network, i.e., each direct connection of two
places in the network is contained at least in one row. All numbers in
one line are separated by one space. Each block ends with a line
containing just ‘0’. The last block has only one line with N = 0.
Output
The output contains for each block except the last in the input file
one line containing the number of critical places.
Sample Input
5
5 1 2 3 4
0
6
2 1 3
5 4 6 2
0
0
1
2
3
4
5
6
7
8
Sample Output
1
2
题目大意:给出一个n点无向图,求图中割点个数
可以用Tarjan算法求割点
割点:在无向连通图中,如果将其中一个点以及所有连接该点的边去掉,图就不再连通,那么这个点就叫做割点
对于根节点,判断是不是割点,只需要计算其子树数量,如果有2棵即以上的子树,就是割点。因为如果去掉这个点,这两棵子树就不能互相到达。
对于非根节点,若其子树的节点均没有指向u的祖先节点的回边,说明删除u之后,根结点与u的子树的节点不再连通;则节点u为割点。即对于边(u, v),如果low[v]>=dfn[u],此时u就是割点。
用邻接矩阵去重边
代码:
#include
#include
#include
#include
using namespace std;
const int N = 100+20;
struct node
{
int v,next;
} e[N * N];
bool instack[N],cut[N];
int first[N],dfn[N],low[N];
int g[N][N];
int cnt, tot, time, root;
void adde (int u, int v)
{
e[tot].v = v;
e[tot].next = first[u];
first[u] = tot++;
}
void tarjan (int u, int pre)
{
dfn[u] = low[u] = ++time;
instack[u] = 1;
int cnt = 0;
for (int i = first[u]; ~i; i = e[i].next)
{
int v = e[i].v;
if (v == pre) continue;
if (!dfn[v])
{
tarjan(v, u);
cnt++;
if (low[u] > low[v]) low[u] = low[v];
if (root == u && cnt > 1) cut[u] = 1; //判断根节点是否是割点
else if (u != root && low[v] >= dfn[u]) cut[u] = 1; //判断非根节点是否是割点
}
else
low[u] = min(low[u], dfn[v]);
}
}
void init ()
{
memset (dfn, 0, sizeof(dfn));
memset (low, 0, sizeof(low));
memset (instack, 0, sizeof(instack));
memset (cut, 0, sizeof(cut));
memset (first, -1, sizeof(first));
memset(g,0,sizeof(g));
tot =time = 0;
}
int main()
{
int n;
int u, v;
while (~scanf("%d", &n), n)
{
init();
while (scanf("%d", &u)&&u)
{
while (getchar() != '\n')
{
scanf("%d", &v);
g[u][v]=1;
g[v][u]=1;
}
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(g[i][j])
adde(i,j);
root = 1;
tarjan (1, -1);
int ans = 0;
for (int i = 1; i <= n; ++i)
if (cut[i])
ans++;
printf("%d\n", ans);
}
return 0;
}