题目地址:http://poj.org/problem?id=1144
题目大意:多组数据,每组数据以0结束,文件也以0结束。对于每组数据第一行n表示点数,接下来至多n行,每行至多n个数,第i个数表示这个点和这一行的第一个数有边,求重要的地方的数目。
重要的地方:删去该点使图分成多部分。
读完题就知道这是个无向图求割点的裸题了……但是读入比较坑,当时没能想出来简单的方法,就gets直接读了。其实我们可以scanf()一个然后getchar()一下,判断是不是回车就行了。
无向图求割点我是看的汝佳大神的训练指南上的,大神勿喷~
代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int size = 100010;
int to[size],next[size],head[size],tot;
void build(int f,int t)
{
to[++tot] = t;
next[tot] = head[f];
head[f] = tot;
}
int dfs_clock,pre[size];
bool is_cut[size];
int dfs(int u,int fa)
{
int lowu = pre[u] = ++dfs_clock;
int child = 0;
for(int i = head[u];i;i = next[i])
{
int v = to[i];
if(!pre[v])
{
child ++;
int lowv = dfs(v,u);
lowu = min(lowu,lowv);
if(lowv >= pre[u]) //如果V能练到的最早的点编号比U编号还要大,说明v和u上面的部分联通必须要经过u,所以u是割点
{
is_cut[u] = true;
}
}
else if(pre[v] < pre[u] && v != fa)
{
lowu = min(lowu,pre[v]);
}
}
if(fa == -1 && child <= 1) is_cut[u] = false; //如果它入读为0并且他只有1个儿子或者没有儿子,它就是不是割点;
return lowu;
}
char in[size];
int n,m;
int main()
{
while(233)
{
memset(head,0,sizeof(head));
memset(to,0,sizeof(to));
dfs_clock = 0;
tot = 0;
memset(next,0,sizeof(next));
memset(is_cut,0,sizeof(is_cut));
memset(pre,0,sizeof(pre));
scanf("%d",&n);
if(n == 0) break;
getchar();
gets(in);
while(in[0] != '0')
{
int a = 0,i = 0;
while(in[i] != ' ') a *= 10,a += in[i] - '0',i ++;
i ++;
for( ;i < strlen(in);i ++)
if(in[i] != ' ')
{
int b = 0;
while(i < strlen(in) && in[i] != ' ') b *= 10,b += in[i]-'0',i ++;
build(a,b);
build(b,a);
}
gets(in);
}
for(int i = 1;i <= n;i ++)
{
if(!pre[i])
{
dfs(i,-1);
}
}
int cnt = 0;
for(int i = 1;i <= n;i ++)
{
if(is_cut[i]) cnt ++;
}
printf("%d\n",cnt);
}
return 0;
}