【图论】割点、桥、双连通

连通分量

个数可以通过一次BFS或者DFS得到


割点和桥

可以枚举删除每一个点或者每一条边,判断连通分量个数是否增加


更好的方法

 

该算法是R.Tarjan发明的。对图深度优先搜索,定义DFS(u)为u在搜索树(以下简称为树)中被遍历到的次序号。定义Low(u)为u或u的子树中能通过非父子边追溯到的最早的节点,即DFS序号最小的节点。

一个顶点u是割点,当且仅当满足(1)或(2) 

(1) u为树根,且u有多于一个子树。 

(2) u不为树根,且满足存在(u,v)为树枝边(或称父子边,即u为v在搜索树中的父亲),使得DFS(u)<=Low(v)


一条无向边(u,v)是桥,当且仅当(u,v)为树枝边,且满足DFS(u)<Low(v)

void dfs(int u,int fa)
{int child=0;pre[u]=low[u]=++tim;for(int e=fst[u];e!=-1;e=nxt[e]){int v=s[e].y;if(!pre[v]){child++;dfs(v,u);low[u]=min(low[u],low[v]);if(low[v]>=pre[u])cut[u]++;if(low[v]>pre[u])bridge[e]=1;}elseif(pre[v]<pre[u] && v!=fa)	//v!=falow[u]=min(low[u],pre[v]);}if(fa<0&&child==1)cut[u]=0;
}


需要注意的是:

1.如果i是root,那么去掉i后,连通分量个数增加cut[i]-1个。如果i不是root,那么连通分量增加cut[i]个

2.无向图  bridge[e]=1  bridge[e+1]同样应标注为1(bridge[e-1])


双连通

 

双连通分点双联通和边双联通

对于一个连通图,若任意两点至少存在两条“点不重复”的路径,则此连通图是点-双连通的,意味着任意的两条边都是在同一个简单环上,即内部无割顶。点-双连通的极大子图叫做双连通分量或块。定理:不同双联通分量最多只有一个公共点,且它一定是割顶,任意割顶都是至少两个不同双连通分量的公共点。

对于一个连通图,若任意两点至少存在两条“边不重复”的路径,则此连通图是边-双连通的,意味着只需要每条边都至少在一个简单环中,即所有边都不是桥。边-双连通的极大子图叫做边-双连通分量,除了桥不属于任何边-双连通分量之外,其他每条边恰好属于一个边-双连通分量,而且把所有桥删除之后,每个连通分量对应原图中的一个边-双连通分量。


对于点双连通分支,实际上在求割点的过程中就能顺便把每个点双连通分支求出。建立一个栈,存储当前双连通分支,在搜索图时,每找到一条树枝边或后向边(非横叉边),就把这条边加入栈中。如果遇到某时满足DFS(u)<=Low(v),说明u是一个割点,同时把边从栈顶一个个取出,直到遇到了边(u,v),取出的这些边与其关联的点,组成一个点双连通分支。割点可以属于多个点双连通分支,其余点和每条边只属于且属于一个点双连通分支。



对于边双连通分支,求法更为简单。只需在求出所有的桥以后,把桥边删除,原图变成了多个连通块,则每个连通块就是一个边双连通分支。桥不属于任何一个边双连通分支,其余的边和每个顶点都属于且只属于一个边双连通分支。

有重边的 边-双连通分量 应尤其注意,因为重边也算不同的边。解决方案是用边判断,而不是利用v!=fa判断能否由pre[v]更新low[u]

void dfs(int u,int fa)
{tim++;low[u]=pre[u]=tim;for(int e=fst[u];e!=-1;e=nxt[e]){int w=e;if (e%2)w++;else w--;int v=s[e].y;if(!pre[v]){dfs(v,e);low[u]=min(low[u],low[v]);if (low[v]>pre[u])bridge[e]=bridge[w]=1;}else//if(pre[v]<pre[u] && v != fa)if (pre[v]<pre[u] && (e!=fa && w!=fa))low[u]=min(low[u],pre[v]);}
}

 

void dfs(int u)
{tim++;pre[u]=low[u]=tim;for(int e=fst[u];e!=-1;e=nxt[e]){int w=e;if(w%2)w++;else w--;int v=s[e].y;if(!pre[v]){flag[e]=flag[w]=1;dfs(v);low[u]=min(low[u],low[v]);if(low[v]>pre[u])cnt[e]=cnt[w]=1;}else if(pre[v]<pre[u]&&!flag[e])  //判断边而不是判断点 {flag[e]=flag[w]=1;low[u]=min(low[u],pre[v]);}}
}



构造双连通图

 

一个有桥的连通图,如何把它通过加边变成边双连通图?方法为首先求出所有的桥,然后删除这些桥边,剩下的每个连通块都是一个双连通子图。把每个双连通子图收缩为一个顶点,再把桥边加回来,最后的这个图一定是一棵树,边连通度为1。

统计出树中度为1的节点的个数,即为叶节点的个数,记为leaf。则至少在树上添加(leaf+1)/2条边,就能使树达到边二连通,所以至少添加的边数就是(leaf+1)/2。具体方法为,首先把两个最近公共祖先最远的两个叶节点之间连接一条边,这样可以把这两个点到祖先的路径上所有点收缩到一起,因为一个形成的环一定是双连通的。然后再找两个最近公共祖先最远的两个叶节点,这样一对一对找完,恰好是(leaf+1)/2次,把所有点收缩到了一起。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int m,tn,n;
struct path{int x,y;}s[20001];
int fst[20001],nxt[20001];
bool bridge[20001];
int pre[5001],low[5001];
int tim,part,x,y;
int hash[5001],out[5001];void dfs(int u,int fa)
{tim++;low[u]=pre[u]=tim;for(int e=fst[u];e!=-1;e=nxt[e]){int w=e;if (e%2)w++;else w--;int v=s[e].y;if(!pre[v]){dfs(v,e);low[u]=min(low[u],low[v]);if (low[v]>pre[u])bridge[e]=bridge[w]=1;}else//if(pre[v]<pre[u] && v != fa)if (pre[v]<pre[u] && (e!=fa && w!=fa))low[u]=min(low[u],pre[v]);}
}void makeside(int x,int y)
{n++;s[n].x=x;s[n].y=y;nxt[n]=fst[x];fst[x]=n;
}void color(int i)
{hash[i]=part;for(int e=fst[i];e!=-1;e=nxt[e])if (!bridge[e]&&!hash[s[e].y])color(s[e].y);
}void print()
{int z=0;for(int e=1;e<=n;e++)if(bridge[e]){out[hash[s[e].x]]++;out[hash[s[e].y]]++;}for(int i=1;i<=part;i++)if(out[i]==2)z++;cout<<(z+1)/2<<endl;
}int main()
{while(scanf("%d%d",&m,&tn)==2){memset(fst,-1,sizeof(fst));memset(nxt,-1,sizeof(nxt));memset(bridge,0,sizeof(bridge));memset(hash,0,sizeof(hash));memset(out,0,sizeof(out));memset(pre,0,sizeof(pre));memset(low,0,sizeof(low));n=part=tim=0;for(int i=1;i<=tn;i++){scanf("%d%d",&x,&y);makeside(x,y);makeside(y,x);}for(int i=1;i<=m;i++)if(!pre[i])dfs(i,-1);for(int i=1;i<=m;i++)if(!hash[i]){part++;color(i);}print();}		return 0;
}


见题目:

HOJ

1007 SPF

1098 NetWork

1789 Electricity

2360 Redundant Paths

 

POJ

3117 Redundant Paths

3352 Road Construction



参考:

https://www.byvoid.com/blog/biconnect

http://blog.csdn.net/z635457712a/article/details/8229113

http://blog.csdn.net/lyy289065406/article/details/6762370


 

转载于:https://www.cnblogs.com/abgnwl/p/6550352.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/375478.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

奇酷手机显示Log

1、在桌面点击拨号&#xff0c;在拨号盘输入“*20121220#”&#xff0c;进入工程模式;2、看到日志输出等级&#xff0c;点进去 Log print enable 选 enable Java log level 选 LOGV C and C log level 选 LOGV Kernel log level 选 KERN_DEBUG3、完毕 参考网址&#xff1a;http…

getCanonicalPath getAbsolutePath区别

1、在winows环境下它们的区别是 &#xfeff;&#xfeff;getCanonicalPath是标准路径&#xff0c;没有特殊字符&#xff0c;getAbsolutePath是有特殊字符的 2、在AIX系统中它们的区别&#xff1a; 首先编译&#xff1a;javac com/ai/test/BugTest.java 然后运行&#xff1a;ja…

Hbase与hive整合

//hive与hbase整合create table lectrure.hbase_lecture10(sname string, score int) stored by org.apache.hadoop.hive.hbase.HBaseStorageHandler whth serdeproperties("hbase.columns.mapping" :key,cf1:score)tblproperties("hbase.table.name" &q…

C++实现一个http服务器

一个简单的博客后端服务器 github地址&#xff0c;持续更新 设计参考 #define MYSQLPP_MYSQL_HEADERS_BURIED #include "httplib.h" #include "rapidjson/document.h" #include <mysql/mysql.h> #include <iostream> #include <string>…

KMP算法的java实现

package com.trs.utils;public class KMPStr {/** 在KMP算法中&#xff0c;最难求的就是next函数&#xff0c;如何理解next函数是一个难题&#xff0c;特别是knext[k]&#xff0c;这里* 需要指出的是当p[i]!p[j]时&#xff0c;我们只有通过回溯将k的值逐渐减小&#xff0c;貌似…

线段分割法实现微信抢红包

无意间看到的一种实现抢红包的方法&#xff0c;于是用C实现了一下。 将一个红包分成 n 份 具体的思路是&#xff0c;将一个红包看作是一个线段&#xff0c;线段的长就是红包总金额&#xff0c;然后在这个线段上随机切 n-1 刀&#xff0c;分成 n 份&#xff0c;然后抢红包的人依…

JAVA多线程和并发基础面试问答(转载)

JAVA多线程和并发基础面试问答 原文链接&#xff1a;http://ifeve.com/java-multi-threading-concurrency-interview-questions-with-answers/ 多线程和并发问题是Java技术面试中面试官比较喜欢问的问题之一。在这里&#xff0c;从面试的角度列出了大部分重要的问题&#xff0c…

Linux的学习--crontab

之前了解过一点crontab&#xff0c;前段时间比较闲&#xff0c;就熟悉了一下&#xff0c;今天总结记录一下。 crontab命令常见于Unix和类Unix的操作系统之中&#xff0c;用于设置周期性被执行的指令。该命令从标准输入设备读取指令&#xff0c;并将其存放于"crontab"…

C++雪花算法实现

看来一下雪花算法的实现方法&#xff0c;用 c试着实现了一下&#xff0c;这里仅仅是实现了算法的流程&#xff0c;但是具体的细节&#xff0c;如并发、多线程访问等等没有具体考虑。 雪花算法的简单讲解参考 #include <sys/select.h> #include <iostream> #includ…

CAlayer层的属性

iOS开发UI篇—CAlayer层的属性 一、position和anchorPoint 1.简单介绍 CALayer有2个非常重要的属性&#xff1a;position和anchorPoint property CGPoint position; 用来设置CALayer在父层中的位置 以父层的左上角为原点(0, 0) property CGPoint anchorPoint; 称为“定位点”、…

Window Linux下实现指定目录内文件变更的监控方法

转自&#xff1a;http://qbaok.blog.163.com/blog/static/10129265201112302014782/ 对于监控指定目录内文件变更&#xff0c;window 系统提供了两个未公开API&#xff1a;SHChangeNotifyRegister SHChangeNotifyDeregister 分别用于注册Notify以及监视。 同时&#xff0c;还提…

Odoo9发行说明

2015年10月1日&#xff0c;期待已久的Odoo9正式发布。本文是Odoo9正式版发行说明&#xff0c;基于官网资料翻译。 译者: 苏州-微尘原文地址&#xff1a;https://www.odoo.com/page/odoo-9-release-notes译文地址&#xff1a;http://blog.csdn.net/wangnan537/article/details/4…

揭秘史上最完美一步到位的搭建Andoriod开发环境

Windows环境下Android开发环境搭建虽然不难而且网上资料众多&#xff0c;但是众多资料如出一折 忽略了很多细节&#xff0c;最终还是没能达到满意效果。 基本步骤如下&#xff1a;JDK安装、环境变量配置、Eclipse下载、AndoriodSDK下载安装、下载配置ADT但是到这里还不算完美搞…

基于OpenCv的人脸检测、识别系统学习制作笔记之二

在网上找到了一个博客&#xff0c;里面有大量内容适合初学者接触和了解人脸检测的博文&#xff0c;正好符合我目前的学习方面&#xff0c;故将链接放上来&#xff0c;后续将分类原博客的博文并加上学习笔记。 传送门&#xff1a; http://blog.sina.com.cn/s/articlelist_160256…

URL 化

URL化。编写一种方法&#xff0c;将字符串中的空格全部替换为%20。假定该字符串尾部有足够的空间存放新增字符&#xff0c;并且知道字符串的“真实”长度。&#xff08;注&#xff1a;用Java实现的话&#xff0c;请使用字符数组实现&#xff0c;以便直接在数组上操作。&#xf…

第一章 00 StringUtil.cpp和StringUtil.hh分析

1 /*2 * StringUtil.hh3 *4 * Copyright 2002, Log4cpp Project. All rights reserved.5 *6 * See the COPYING file for the terms of usage and distribution.7 */8 头文件的说明&#xff0c;以及与版权相关的说明一般都会放置在文件的开始位置 9 #ifndef _LOG4CPP_STR…

【SQL】服务器环境下的SQL

一、大型数据库的三层体系结构 web服务器&#xff1a;比如在淘宝页面上&#xff0c;输入“牛肉干”&#xff0c;就是web服务器来处理&#xff0c;提交给应用服务器。 应用服务器&#xff1a;在获取到“牛肉干”这个请求后&#xff0c;应用服务器决定如何汇集结果&#xff0c;并…

【置顶】全局变量的好处与坏处

近日在做项目的过程中对plsql的使用非常多&#xff0c;主要是编写存储过程实现业务逻辑。但是在coding的过程中遇到非常奇怪的问题。 问题是&#xff1a;在package包头中定义了一个变量&#xff0c;current_time : sysdate,然后在procedure使用这个定义的变量&#xff0c;直接i…

三个线程按顺序输出数字

当 n 3N 时&#xff0c;线程1输出 当 n 3N 1 时&#xff0c;线程2输出 当 n 3N 2 时&#xff0c;线程3输出 最终的输出为 0、1、2、3、4、5、6、7、8、10 #include <iostream> #include <thread> #include <mutex> #include <condition_variable&g…

TextView实现自动滚动滚动.

必须有要四个属性: android:ellipsize"marquee"; android:focusable"true";android"focusableInTouchMode"true";android:singleLine"true"; <TextViewandroid:layout_width"fill_parent"android:layout_height&quo…