hihoCoder_#1183_连通性一·割边与割点

#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
分析:tarjan求无向连通图的割点与割边(桥)。

引理:对于连通无向图G={V,E},S={V,T}为G的一个DFS树,则结点u是G的割点当且仅当下面条件之一被满足:

1.  u是T的根且u至少有两个儿子

2.  u不是T的根且存在u的某个儿子w,使得从w或者w的后代没有边连回u的祖先(注意,不是连回u本身)。

类似于割点,我们可以定义无向连通图的桥(bridge):如果删除一条边e后无向图G不再连通,称e为G的桥。桥的判定也不难,只需要在发现T边(u,v)时进行判断。如果v后它的后代无法连回u或者u的祖先,则删除(u, v)后u和v不连通。即:发现T边(u, v)并递归遍历v后若dfn[u]<low[v],则(u, v)为桥。类似于割顶,我们称没有桥的图为边连通图。如果一个无向图是边连通的,可以把它的边定向,得到一个强连通的有向图。

关于图的强联通分量,块,割点,桥,请点击这里:http://blog.csdn.net/shiqi_614/article/details/7833628

void tarjan(int u,int father){ //father是u的父节点
    dfn[u]=low[u]=++idx;
    int children=0; //计算u的儿子节点个数
    for(int i=0;i<graph[u].size();i++){
        int v=graph[u][i];
        if(v==father) continue;
        if(!dfn[v]){
            children++;
            tarjan(v,u);
            low[u]=min(low[u],low[v]);

            //判断是否割点,点可能进入多次,所以用set方便
            if((father==u&&children>1)||(father!=u&&low[v]>=dfn[u])){
                vertex.insert(u);
                judge=true;
            }

            //判断是否割边(桥)
            if(low[v]>dfn[u])
                edge[ed++]=Edge(min(u,v),max(u,v));
        }
        else //不需判断是否在栈中,
            low[u]=min(low[u],dfn[v]);
    }
}
题目链接:http://hihocoder.com/problemset/problem/1183

代码清单:

#include<map>
#include<set>
#include<queue>
#include<stack>
#include<cmath>
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;

const int maxn = 20000 + 5;
const int maxv = 100000 + 5;

int N,M,a,b;
vector<int>graph[maxn];
int dfn[maxn];
int low[maxn];
int ve,ed,root,idx;

bool judge;
set<int>vertex;
struct Edge{
    int u,v;
    Edge(){}
    Edge(int u,int v){
        this -> u = u;
        this -> v = v;
    }
}edge[maxv];

bool cmp(Edge a,Edge b){
    if(a.u==b.u) return a.v<b.v;
    return a.u<b.u;
}

void init(){
    for(int i=0;i<maxn;i++)
        graph[i].clear();
    vertex.clear();
    memset(dfn,0,sizeof(dfn));
    memset(low,0,sizeof(low));
    ve=0; ed=0; idx=0;
    judge=false;
}

void input(){
    scanf("%d%d",&N,&M);
    for(int i=0;i<M;i++){
        scanf("%d%d",&a,&b);
        graph[a].push_back(b);
        graph[b].push_back(a);
    }
}

void tarjan(int u,int father){ //father是u的父节点
    dfn[u]=low[u]=++idx;
    int children=0; //计算u的儿子节点个数
    for(int i=0;i<graph[u].size();i++){
        int v=graph[u][i];
        if(v==father) continue;
        if(!dfn[v]){
            children++;
            tarjan(v,u);
            low[u]=min(low[u],low[v]);

            //判断是否割点,点可能进入多次,所以用set方便
            if((father==u&&children>1)||(father!=u&&low[v]>=dfn[u])){
                vertex.insert(u);
                judge=true;
            }

            //判断是否割边(桥)
            if(low[v]>dfn[u])
                edge[ed++]=Edge(min(u,v),max(u,v));
        }
        else //不需判断是否在栈中,
            low[u]=min(low[u],dfn[v]);
    }
}

void solve(){
    tarjan(1,1);
    sort(edge,edge+ed,cmp);
    if(!judge) printf("Null\n");
    else{
        set<int>::iterator it=vertex.begin();
        for(;it!=vertex.end();it++)
            printf("%d ",*it);
        printf("\n");
    }
    for(int i=0;i<ed;i++){
        printf("%d %d\n",edge[i].u,edge[i].v);
    }
}

int main(){
    init();
    input();
    solve();
    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-11-01 18:10:54

hihoCoder_#1183_连通性一·割边与割点的相关文章

hihoCoder 1183 连通性一&#183;割边与割点(Tarjan求割点与割边)

#1183 : 连通性一·割边与割点 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 还记得上次小Hi和小Ho学校被黑客攻击的事情么,那一次攻击最后造成了学校网络数据的丢失.为了避免再次出现这样的情况,学校决定对校园网络进行重新设计. 学校现在一共拥有N台服务器(编号1..N)以及M条连接,保证了任意两台服务器之间都能够通过连接直接或者间接的数据通讯. 当发生黑客攻击时,学校会立刻切断网络中的一条连接或是立刻关闭一台服务器,使得整个网络被隔离成两个独立的部分. 举个

HihoCoder 1183 : 连通性一&#183;割边与割点

连通性一·割边与割点 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 还记得上次小Hi和小Ho学校被黑客攻击的事情么,那一次攻击最后造成了学校网络数据的丢失.为了避免再次出现这样的情况,学校决定对校园网络进行重新设计. 学校现在一共拥有N台服务器(编号1..N)以及M条连接,保证了任意两台服务器之间都能够通过连接直接或者间接的数据通讯. 当发生黑客攻击时,学校会立刻切断网络中的一条连接或是立刻关闭一台服务器,使得整个网络被隔离成两个独立的部分. 举个例子,对于以下的

hihocoder1183 连通性一&#183;割边与割点

输入 第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小的排在前面.

Tarjan的学习笔记 求割边求割点

博主图论比较弱,搜了模版也不会用... 所以决心学习以下tarjan算法. 割点和割边的概念不在赘述,tarjan能在线性时间复杂度内求出割边. 重要的概念:时间戟,就是一个全局变量clock记录访问结点的时间.一个无向图dfs会形成一个森林,当图只有一个连通分量时,就只有一棵树. 由于在无向图中,除了树边,其他都是反向边.可以画个图感受一下,可以反证的,如果有其他类型的边,那么dfs先沿着那些边跑图的,那么那些边就不存在. 如果结点是树根,那么它是割点的充要条件就是它有两个子结点. 定理 对于

hihoCoder_#1184_连通性二&#183;边的双连通分量

#1184 : 连通性二·边的双连通分量 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 在基本的网络搭建完成后,学校为了方便管理还需要对所有的服务器进行编组,网络所的老师找到了小Hi和小Ho,希望他俩帮忙. 老师告诉小Hi和小Ho:根据现在网络的情况,我们要将服务器进行分组,对于同一个组的服务器,应当满足:当组内任意一个连接断开之后,不会影响组内服务器的连通性.在满足以上条件下,每个组内的服务器数量越多越好. 比如下面这个例子,一共有6个服务器和7条连接: 其中包

hihoCoder_#1190_连通性&#183;四&#183;点的双连通分量(块)

#1190 : 连通性·四 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi和小Ho从约翰家回到学校时,网络所的老师又找到了小Hi和小Ho. 老师告诉小Hi和小Ho:之前的分组出了点问题,当服务器(上次是连接)发生宕机的时候,在同一组的服务器有可能连接不上,所以他们希望重新进行一次分组.这一次老师希望对连接进行分组,并把一个组内的所有连接关联的服务器也视为这个组内的服务器(注意一个服务器可能属于多个组). 这一次的条件是对于同一个组满足:当组内任意一个服务器宕

tarjan,割边,桥,割点

这里是tarjan的基础知识, 求割点和割边 先来求割边, #include <cstdio> #include <iostream> #include <bits/stdc++.h> using namespace std; typedef long long ll; typedef unsigned long long ull; #define ls (t<<1) #define rs ((t<<1)|1) #define mid ((l+r

hihoCoder_#1185_连通性&#183;三&#183;强连通分量

#1185 : 连通性·三 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 暑假到了!!小Hi和小Ho为了体验生活,来到了住在大草原的约翰家.今天一大早,约翰因为有事要出去,就拜托小Hi和小Ho忙帮放牧. 约翰家一共有N个草场,每个草场有容量为W[i]的牧草,N个草场之间有M条单向的路径. 小Hi和小Ho需要将牛羊群赶到草场上,当他们吃完一个草场牧草后,继续前往其他草场.当没有可以到达的草场或是能够到达的草场都已经被吃光了之后,小hi和小Ho就把牛羊群赶回家. 一开

Tarjan系列1

tajan的dfs树系列算法: 求解割点,桥,强连通分量,点双联通分量,边双联通分量: tajan是一个dfs,把一个图变成一个dfs树结构, dfs树结构,本质是通过一个没有任何要求的dfs把图的边分为:树边和返祖边: 树边:dfs中父节点与其未曾遍历过的子节点间的边, 返祖边:父节点与他的dfs中曾作为该父节点祖先的子节点间的边 在有向图中,除了这二种边外,还有父节点与曾遍历过的子节点间的边,然而这个子节点不是父节点的祖先, 然而这种边在tarjan中没有意义,我们所求的东西用不上她们 伪代