HihoCoder 1183 : 连通性一·割边与割点(模板)

连通性一·割边与割点

时间限制:10000ms
单点时限:1000ms
内存限制:256MB

描述

还记得上次小Hi和小Ho学校被黑客攻击的事情么,那一次攻击最后造成了学校网络数据的丢失。为了避免再次出现这样的情况,学校决定对校园网络进行重新设计。

学校现在一共拥有N台服务器(编号1..N)以及M条连接,保证了任意两台服务器之间都能够通过连接直接或者间接的数据通讯。

当发生黑客攻击时,学校会立刻切断网络中的一条连接或是立刻关闭一台服务器,使得整个网络被隔离成两个独立的部分。

举个例子,对于以下的网络:

每两个点之间至少有一条路径连通,当切断边(3,4)的时候,可以发现,整个网络被隔离为{1,2,3},{4,5,6}两个部分:

若关闭服务器3,则整个网络被隔离为{1,2},{4,5,6}两个部分:

小Hi和小Ho想要知道,在学校的网络中有哪些连接和哪些点被关闭后,能够使得整个网络被隔离为两个部分。

在上面的例子中,满足条件的有边(3,4),点3和点4。

 

提示:割边&割点

 

输入

第1行:2个正整数,N,M。表示点的数量N,边的数量M。1≤N≤20,000, 1≤M≤100,000

第2..M+1行:2个正整数,u,v。表示存在一条边(u,v),连接了u,v两台服务器。1≤u<v≤N

保证输入所有点之间至少有一条连通路径。

输出

第1行:若干整数,用空格隔开,表示满足要求的服务器编号。从小到大排列。若没有满足要求的点,该行输出Null

第2..k行:每行2个整数,(u,v)表示满足要求的边,u<v。所有边根据u的大小排序,u小的排在前,当u相同时,v小的排在前面。若没有满足要求的边,则不输出

样例输入
6 7
1 2
1 3
2 3
3 4
4 5
4 6
5 6
样例输出
3 4
3 4
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<cstring> 
using namespace std;
int const maxn=10010;
int const maxm=200010;
int low[maxn],dfn[maxn],times;
int Laxt[maxn],Next[maxm],To[maxm],cnt;
int cut_num,node[maxn];
bool NUll=true;

struct in{
    int x,y;
}s[maxm];//割边

bool cmp(in a ,in b)
{
    if(a.x==b.x) return a.y<b.y;
    return a.x<b.x;
}

void add(int u,int v)
{
    Next[++cnt]=Laxt[u];
    Laxt[u]=cnt;
    To[cnt]=v;
}

int dfs(int u,int pre)
{
    int son=0;
    dfn[u]=low[u]=++times;
    for(int i=Laxt[u];i;i=Next[i]){
        if(To[i]==pre) 
               continue;//不然自环了 
        if(!dfn[To[i]]){
            son++;
            dfs(To[i],u);
            low[u]=min(low[u],low[To[i]]);
            if(dfn[u]<low[To[i]]){//割边 
                s[++cut_num].x=min(u,To[i]);
                s[cut_num].y=max(u,To[i]);
            }
            if(u!=pre&&dfn[u]<=low[To[i]]){//非根割点 
                NUll=false;
                node[u]=1;
            }
        }
        else low[u]=min(low[u],dfn[To[i]]);
    }
    if(u==pre&&son>1) {//根割点 
         node[u]=1;
         NUll=false;
    }
}

void _cout(int n)
{
    int fir=0;
    if(NUll) printf("Null");
    else 
    for(int i=1;i<=n;i++){
        if(node[i]){
            printf("%d ",i);
        }
    }
    printf("
");
    sort(s+1,s+cut_num+1,cmp);
    for(int i=1;i<=cut_num;i++)
        printf("%d %d
",s[i].x,s[i].y);//当然无重边,不然也得set判重 
}

int main()
{
    int n,m,i,j,u,v;
    scanf("%d%d",&n,&m);
    for(i=1;i<=m;i++){
        scanf("%d%d",&u,&v);
        add(u,v);
        add(v,u);
    }
    dfs(1,1);//如果是森林,得for扫描一遍!dfn 
    _cout(n);
    return 0;
}
原文地址:https://www.cnblogs.com/hua-dong/p/7788263.html