POJ 1523 浅谈无向图TarJan连通块割顶分割技术

本文介绍了一道POJ题目,涉及无向图的割点寻找及删除割点后的连通分量计算。通过DFS转化图并利用TarJan算法,可以确定割点及其导致的连通分量数量。题目难点在于特殊的输入格式处理,但实际算法实现相对直接,旨在巩固图论知识和编程技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这里写图片描述
世界真的很大
昨天晚上还有十分钟的时候开始写这道题,未果
今天上午考试下午讲课晚上好不容易有时间来写这道题,成功
犯了一个小小的错误不必深究
POJ的读入方式怎么这么恶心woc。。

看题先:

description:

无向图求割点和去除割点后连通分量的个数

input:

The input will contain the description of several networks. A network description will consist of pairs of integers, one pair per line, that identify connected nodes. Ordering of the pairs is irrelevant; 1 2 and 2 1 specify the same connection. All node numbers will range from 1 to 1000. A line containing a single zero ends the list of connected nodes. An empty network description flags the end of the input. Blank lines in the input file should be ignored.

output:

For each network in the input, you will output its number in the file, followed by a list of any SPF nodes that exist.

The first network in the file should be identified as “Network #1”, the second as “Network #2”, etc. For each SPF node, output a line, formatted as shown in the examples below, that identifies the node and the number of fully connected subnets that remain when that node fails. If the network has no SPF nodes, simply output the text “No SPF nodes” instead of a list of SPF nodes.

在这种一读就是板子题的东西下,**的出题人把考点放在了读入方式上。。。

想方设法读入完成后,这道题就是一个求割点然后判断每一个割点删去后会把联通图分成多少块
把图转化为DFS树之后相当于答案就是其子树个数+1,因为还有父亲边的方向。根节点需要特判一下,统计其有多少个子树,这个也可以在tarjan里面做到

完整代码:

#include<stdio.h>
#include<cstring>
#include<algorithm>
using namespace std;

struct edge
{
    int u,v,last;
}ed[4000010];

int num=0,idx=0,cnt=0,tot=0,flag=1,son=0;
int head[10010],low[10010],dfn[10010],src[10010],fa[10010];

void add(int u,int v)
{
    num++;
    ed[num].v=v;
    ed[num].last=head[u];
    head[u]=num;
}

void tarjan(int u)
{
    dfn[u]=low[u]=++idx;
    for(int i=head[u];i;i=ed[i].last)
    {
        int v=ed[i].v;
        if(i==(fa[u]^1)) continue ;
        if(!dfn[v])
        {
            fa[v]=i;
            tarjan(v);
            low[u]=min(low[v],low[u]);
            if(low[v]>=dfn[u])
            {
                if(u!=1) src[u]++;
                else son++;
            }
        }
        else low[u]=min(low[u],dfn[v]);
    }
}

void init()
{
    memset(head,0,sizeof(head));
    memset(dfn,0,sizeof(dfn));
    memset(low,0,sizeof(low));
    memset(src,0,sizeof(src));
    memset(fa,0,sizeof(fa));
    num=1,idx=0,cnt=0,flag=1,son=0;
}

int main()
{
    while(1)
    {
        init();
        while(1)
        {
            int u,v;
            scanf("%d",&u);
            if(!u) break ;
            scanf("%d",&v);
            add(u,v),add(v,u);
            cnt++;
        }
        if(cnt==0) break ;
        tarjan(1);
        printf("Network #%d\n",++tot);
        if(son>1) src[1]=son-1;
        for(int i=1;i<=1000;i++)
            if(src[i])
            {
                flag=0;
                printf("  SPF node %d leaves %d subnets\n",i,src[i]+1);
            }
        if(flag) printf("  No SPF nodes\n");
        printf("\n");
    }
    return 0;
}
/*
EL PSY CONGROO
*/

嗯,就是这样


(P.S. 感觉最近题解越来越水了。。真不是因为我懒得写,只不过都是些板子题。。。主要目的是练手然后总结方法。。233)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值