题目大意:
TLC电话线路公司正在新建一个电话线路网络。他们将一些地方(这些地方用1~N的整数标明,任何两个地方的标号都不相同)用电话线路连接起来。这些线路是双向的,每条线路连接两个地方,并且每个地方的电话线路都连接到一个电话交换机。每个地方都有一个电话交换机。从每个地方都可以到达其他一些地方(如果有线路连接的话),然而这些线路不一定必须是直接连接的,也可以是通过几个电话交换机到达另外一个地方。但是有时会因为电力不足导致某个地方的交换机不能工作。TLC的官员意识到一旦出现这种情况(在某个地方的交换机不工作,即这个结点与其他结点之间的线路都断开了),除了这个出现故障的地方是不可达外,还可能导致其他一些(本来连通的)地方也不再连通。称这个地方为关节点。
现在TLC的官员努力想写一个程序来找到关节点的数目。请帮助他们。
解题思路:
求无向图的割点,tarjan算法
代码如下:
#include<cstdio>
#include<cstring>
#define MAXN 105
int Edge[MAXN][MAXN];
int visited[MAXN];
int n;
int tmpfn;
int dfn[MAXN];
int low[MAXN];
int son;
int critical;
int subnet[MAXN];
int min(int a,int b)
{
if(a>b) return b;
else return a;
}
void dfs(int u)
{
for(int v=1;v<=n;v++)
{
if(Edge[u][v])
{
if(!visited[v])
{
visited[v]=1;
tmpfn++;
dfn[v]=low[v]=tmpfn;
dfs(v);
low[u]=min(low[u],low[v]);
if(low[v]>=dfn[u])
{
if(u!=1&&!subnet[u])
{
subnet[u]=1;
critical++;
}
if(u==1)
son++;
}
}
else
low[u]=min(low[u],dfn[v]);
}
}
}
void init()
{
low[1]=dfn[1]=1;
tmpfn=1;
son=0;
memset(visited,0,sizeof(visited));
visited[1]=1;
critical=0;
memset(subnet,0,sizeof(subnet));
}
int main()
{
int i;
int u,v;
while(scanf("%d",&n),n)
{
getchar();
memset(Edge,0,sizeof(Edge));
char buf[128];
int u,v;
while(1)
{
int k=0;
int first=1;
gets(buf);
while(sscanf(buf+k,"%d",&v)==1)
{
if(first)
{
first=0;u=v;
}
else
Edge[u][v]=Edge[v][u]=1;
while(buf[k]&&buf[k]==' ') k++;
while(buf[k]&&buf[k]!=' ') k++;
}
if(u==0) break;
}
init();
dfs(1);
if(son>1) critical++;
printf("%d\n",critical);
}
return 0;
}