[学习][poj1523]割点 SPF

题目背景
poj1523

题目描述
Consider the two networks shown below. Assuming that data moves around these networks only between directly connected nodes on a peer-to-peer basis, a failure of a single node, 3, in the network on the left would prevent some of the still available nodes from communicating with each other. Nodes 1 and 2 could still communicate with each other as could nodes 4 and 5, but communication between any other pairs of nodes would no longer be possible.

Node 3 is therefore a Single Point of Failure (SPF) for this network. Strictly, an SPF will be defined as any node that, if unavailable, would prevent at least one pair of available nodes from being able to communicate on what was previously a fully connected network. Note that the network on the right has no such node; there is no SPF in the network. At least two machines must fail before there are any pairs of available nodes which cannot communicate.
这里写图片描述

题目大意
给一个无向图,找出其中的割点,并求出删除每一个割点时图被分成了多少块。(多组数据)

输入格式
输入包含若干网络描述。网络描述由成对的整数组成,每行一对,表示连接的节点。和给出的顺序无关:1 2和2 1代表相同的连接。所有节点编号从1到1000不等。每组数据以一个0结尾。最后单独一个0表示读入结束。

输出格式
对于输入中的每一个网络,您将在文件中输出其编号,然后列出存在的任何SPF节点(割点)。文件中的第一个网络应输出为“Network #1”,二是“Network #2”。每个SPF节点输出一行,格式如下面的例子所示,输出删除该割点后该图变成了多少个连通块。如果网络没有SPF节点,只需输出文本“No SPF nodes”,而不是一个SPF节点列表。

样例数据
输入

1 2
5 4
3 1
3 2
3 4
3 5
0

1 2
2 3
3 4
4 5
5 1
0

1 2
2 3
3 4
4 6
6 3
2 5
5 1
0

0

输出

Network #1
SPF node 3 leaves 2 subnets

Network #2
No SPF nodes

Network #3
SPF node 2 leaves 2 subnets
SPF node 3 leaves 2 subnets

分析:这道题我想得最久的竟然是怎么读入orz(因为已经知道是一道求割点的题了)。割点模板

代码

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<iomanip>
#include<queue>
#include<set>
using namespace std;

int getint()
{
    int sum=0,f=1;
    char ch;
    for(ch=getchar();!isdigit(ch)&&ch!='-';ch=getchar());
    if(ch=='-')
    {
        f=-1;
        ch=getchar();
    }
    for(;isdigit(ch);ch=getchar())
        sum=(sum<<3)+(sum<<1)+ch-48;
    return sum*f;
}

const int maxn=1010;
const int maxm=1000010;
int x,y,cnt,tot=1,num,dep;
int first[maxn],ans[maxn],dfn[maxn],low[maxn],nxt[maxm*2],to[maxm*2];
bool bj,used[maxn];

void addedge(int x,int y)
{
    tot++;
    nxt[tot]=first[x];
    first[x]=tot;
    to[tot]=y;
    tot++;
    nxt[tot]=first[y];
    first[y]=tot;
    to[tot]=x;
}

void tarjan(int root,int u,int fro)
{
    dfn[u]=++dep;//不要用index,linux环境下会死的
    low[u]=dep;

    int child=0;
    for(int p=first[u];p;p=nxt[p])
    {
        int v=to[p];
        if(!dfn[v])
        {
            child++;//儿子数量+1
            tarjan(root,v,p);
            low[u]=min(low[u],low[v]);
            if((u!=root&&low[v]>=dfn[u])||(u==root&&child>1))//如果该点不是根节点,那么删掉它,这个儿子节点以及后面的就成为了一个新连通块;如果该节点是根节点,那么它的儿子数要大于1断掉它才会出现新的连通块
                ans[u]++;//新增连通块+1
        }
        else//之前走过的
            if(p!=(fro^1))//没有走回父亲节点
                low[u]=min(low[u],dfn[v]);//更新low值
    }
}

int main()
{
    freopen("SPF.in","r",stdin);
    freopen("SPF.out","w",stdout);

    while(true)
    {
        x=getint();
        if(x)//读到值
        {
            bj=true;//有图
            y=getint();
            used[x]=used[y]=1;//记一下用没用这个编号(事实证明好像给的编号是连贯的orz)
            addedge(x,y);
        }
        else if(bj)//读到0,而且前面是有图的
        {
            cnt++;//记录第几个图
            for(int i=1;i<=1000;++i)
                if(used[i])
                    if(!dfn[i])//这是担心图本来就有没连通的地方,这样输出就需要多加那些本来就独立的连通块(事实证明给的图也都是保证连通的orz)
                    {
                        num++;//记录连通块个数
                        tarjan(i,i,0);//tarjan找割点
                    }

            cout<<"Network #"<<cnt<<'\n';
            bool bjans=0;
            for(int i=1;i<=1000;++i)
                if(ans[i])
                {
                    bjans=1;//有答案
                    cout<<"  SPF node "<<i<<" leaves "<<ans[i]+num<<" subnets"<<'\n';
                }

            if(!bjans)//没有答案
                cout<<"  No SPF nodes"<<'\n';
            cout<<'\n';
            //这些清零操作都不能忘orz
            tot=1,bj=false,index=0,num=0;//tot一定要取1,这样每条边异或才能得到它的反向边
            memset(used,0,sizeof(used));
            memset(first,0,sizeof(first));
            memset(dfn,0,sizeof(dfn));
            memset(low,0,sizeof(low));
            memset(ans,0,sizeof(ans));
        }
        else break;
    }

    return 0;
}

本题结。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值