POJ1144 tarjan+网络中割点与割边的数量
时间:2020-03-27
本文章向大家介绍POJ1144 tarjan+网络中割点与割边的数量,主要包括POJ1144 tarjan+网络中割点与割边的数量使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
题目链接:http://poj.org/problem?id=1144
割点与割边的数量我们可以通过tarjan的思想从一个点开始对其余点进行访问。访问的顺序构成一棵dfs树,其中根节点到任何一个结点都只有唯一的一条路径。算法基于以下两个定理:
定理一:
dfs树的根结点T是割点当且仅当他有两个或者更多的子节点。因为dfs树上任何点的子树都是不连通的,否则就会构成环,与dfs树的定义矛盾。故定理得证。
定理二 :
dfs树上的非根结点是割点当且仅当u至少存在一个子节点v,v的所有后代都没有回退边连回u的祖先,也就是从v出发能够访问到的最浅的结点比u的深度大。因为此时把u割去之后一定会使得v为根的分支被割离。
根据以上定理,我们只要记录dfs的顺序,每个点的开始访问的最浅dfs深度并进行比较,即low[v]>=low[u]就可以得到割点的数量。对于割边,我们只要u的子结点v有low[v]>num[u]就说明(u,v)是割边。
代码如下:
1 #include<cstdio> 2 #include<vector> 3 #include<string.h> 4 using namespace std; 5 const int maxn=109; 6 int low[maxn],num[maxn];//分别保存dfs树上结点能到达的最浅深度和dfs的访问顺序 7 bool iscut[maxn];//记录是否是割点 8 vector<int>G[maxn];//存边 9 int dfn;//记录递归的顺序,用于给num赋值 10 int ans=0;//ans记录割点的数量 11 int n; 12 void tarjan(int u,int fa)//参数分别是当前搜索的结点以及其父结点 13 { 14 low[u]=num[u]=++dfn;//设置dfs的访问顺序,u是dfs访问的第一个点 15 int child=0;//u的子树的数量 16 for(int i=0;i<G[u].size();i++) 17 { 18 int v=G[u][i]; 19 if(!num[v])//v点没有进入过dfs树,也就是没有访问过 20 { 21 child++; 22 tarjan(v,u); 23 low[u]=min(low[u],low[v]);//low[i]的意义是点i所能到的dfs深度最浅的值,father结点由child结点来更新 24 if(low[v]>=num[u]&&u!=1)//注意要判断u不是根节点,因为定理中是分为非根节点以及根节点进行讨论的,根节点根节点最后讨论 25 { 26 iscut[u]=1; 27 } 28 } 29 // else low[u]=min(low[u],num[v]); 30 else if(num[v]<num[u]&&v!=fa)// fa也是u的邻居,在之前已经访问过; 31 //处理回退边 ,u的子节点可以不通过u访问u以上的结点 32 { 33 low[u]=min(low[u],num[v]); 34 } 35 } 36 if(u==1&&child>=2) 37 { 38 iscut[u]=1;//根结点有两个或以上的独立子树 39 } 40 } 41 int main() 42 { 43 while(scanf("%d",&n)&&n) 44 { 45 int t,k; 46 for(int i=1;i<=n;i++)G[i].clear(); 47 memset(iscut,0,sizeof(iscut)); 48 memset(low,0,sizeof(low)); 49 memset(num,0,sizeof(num)); 50 ans=0; 51 dfn=0; 52 while(scanf("%d",&t)==1&&t) 53 { 54 while(getchar()!='\n') 55 { 56 scanf("%d",&k); 57 G[t].push_back(k); 58 G[k].push_back(t); 59 } 60 } 61 tarjan(1,-1); 62 for(int i=1;i<=n;i++)ans+=iscut[i];//扫描割点的数量 63 64 printf("%d\n",ans); 65 } 66 }
原文地址:https://www.cnblogs.com/randy-lo/p/12580810.html
- CSS魔法堂:说说Float那个被埋没的志向
- Netbeans配置Xdebug
- rpc框架: thrift/avro/protobuf 之maven插件生成java类
- WebComponent魔法堂:深究Custom Element 之 从过去看现在
- 数据可视化-EChart2.0使用总结1
- JavaScript事件概览
- gradle项目与maven项目相互转化
- rpc框架之gRPC 学习 - hello world
- Angular Service入门
- spring:如何用代码动态向容器中添加或移除Bean ?
- WebComponent魔法堂:深究Custom Element 之 标准构建
- druid 数据源 使用属性文件的一个坑
- Angular企业级开发(3)-Angular MVC实现
- spring: 加载远程配置
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- LASSO回归姊妹篇:R语言实现岭回归分析
- 学了这个,三歪再也不想写各种setter了
- 使用 GitLab CI 与 Argo CD 进行 GitOps 实践
- Java 语言中十大“坑爹”功能!
- 面试:说说啥是一致性哈希算法?
- 问一下,线程池里面到底该设置多少个线程?
- 进程和线程基础知识全家桶,30 张图一套带走
- Python-matplotlib 学术柱状图绘制
- 为什么要避免大事务以及大事务如何解决?
- [即时通信IM]群@消息如何实现?
- 利用PySpark对 Tweets 流数据进行情感分析实战
- ConcurrentHashMap源码学习
- HashMap源码学习
- Pytest自动化测试fixture之conftest.py
- ArrayList源码学习