POJ 1144 Network 图论

题目地址: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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值