tarjan
时间:2021-07-12
本文章向大家介绍tarjan,主要包括tarjan使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
Tarjan
作用:
- 求强连通分量(求环)
- 求割点(同上)
- 缩点,将有向图变成有向无环图(进行topsort)
实现:
void tarjan(int x){
low[x]=dfn[x]=++cnt;
sta[++top]=x;//在栈中,表示在同一个强连通分量
vis[x]=1;
for(int i=head[x];i;i=nxt[i]){
int y=ver[i];
if(!dfn[y]){
tarjan(y); low[x]=min(low[x],low[y]);
}
else if(vis[y]) low[x]=min(low[x],dfn[y]);//搜索到的最小栈中节点dfs序
}
if(dfn[x]==low[x]){
int y;
while(y=sta[top--]){//缩点
sd[y]=x; vis[y]=0; if(x==y) break;
val[x]+=val[y];
}
}
}
其中,\(dfn[x]\) 为 \(x\) 的 \(dfs\) 序,而 \(low[x]\) 为在该强连通分量中所能找到的最小的 \(dfs\) 序的值。
如果 \(dfn[x]==low[x]\) ,那么这个点就是割点,此时栈中从 \(sta[top] ——> x\) 就是这个强连通分量的点。
又因为加入栈的顺序是按边加入的,所以我们也能记录强连通分量的边,从而得到图中的环。
我们在缩点之后整个图就变成 \(DAG\) ,就能进行拓扑或者算权值等操作。
例题:
P3387 【模板】缩点
这题是模板题。
我们首先需要把所有点都缩成一个点,然后进行 \(dp\)。
我们怎么进行 \(dp\) 呢,因为我们缩完点之后形成了一个有向无环图,我们可以进行拓扑排序,求出来 \(dp\) 的顺序,然后增加值就行。
代码:
//P3387 【模板】缩点
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int n,m,val[N],top;
int nxt[N],ver[N],tot,head[N],from[N];
int dfn[N],low[N],cnt;
int sta[N],vis[N];//栈表示此时是否有父子关系
int sd[N];//把环上所有点都汇总到一个点
int deg[N],dis[N];
struct node{
int nxt,ver,edge,head,from;
}t[N];
void add(int x,int y){
ver[++tot]=y;from[tot]=x;nxt[tot]=head[x];head[x]=tot;
}
void tarjan(int x){
low[x]=dfn[x]=++cnt;
sta[++top]=x;//在栈中,表示在同一个强连通分量
vis[x]=1;
for(int i=head[x];i;i=nxt[i]){
int y=ver[i];
if(!dfn[y]){
tarjan(y); low[x]=min(low[x],low[y]);
}
else if(vis[y]) low[x]=min(low[x],dfn[y]);//搜索到的最小栈中节点dfs序
}
if(dfn[x]==low[x]){
int y;
while(y=sta[top--]){//缩点
sd[y]=x; vis[y]=0; if(x==y) break;
val[x]+=val[y];
}
}
}
int tot1=0;
void add1(int x,int y,int z){
t[++tot1].ver=y; t[tot1].nxt=t[x].head;
t[tot1].edge=z; t[x].head=tot1;
deg[y]++;
}
void topsort(){
queue<int> q;
for(int i=1;i<=n;i++) if(sd[i]==i&&!deg[i]){
q.push(i); dis[i]=val[i];
}
while(!q.empty()){
int x=q.front() ; q.pop();
for(int i=t[x].head;i;i=t[i].nxt){
int y=t[i].ver;
dis[y]=max(dis[y],dis[x]+val[y]);
deg[y]--;
if(deg[y]==0) q.push(y);
}
}
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++) scanf("%d",&val[i]);
for(int i=1,x,y;i<=m;i++){
scanf("%d%d",&x,&y); add(x,y);
}
for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i);
for(int i=1;i<=m;i++){
int x=sd[from[i]],y=sd[ver[i]]; //没有缩成一个点
if(x!=y) add1(x,y,val[x]);
}
topsort(); int ans=0;
for(int i=1;i<=n;i++) ans=max(ans,dis[i]);
cout<<ans<<endl;
system("pause");
return 0;
}
原文地址:https://www.cnblogs.com/guanlexiangfan/p/15003392.html
- Web层框架对网站中所有异常的统一处理
- Spring MVC__自定义日期类型转换器
- 解决在控制层springmvc框架发出的400状态的错误
- 解决springmvc在单纯返回一个字符串对象时所出现的乱码情况(极速版)
- MySQL日志文件之错误日志和慢查询日志详解
- 采用HTML5之"data-"机制自由提供数据
- Spring和SpringMVC父子的容器之道---[上篇]
- 快速完成(图片旋转,查看原图)
- Jsp中格式化时间戳的常用标签
- 反射+自定义注解---实现Excel数据列属性和JavaBean属性的自动映射
- 后台模板管理系统___左侧菜单数据的异步加载
- Shiro眼皮下玩ajax,玩出302 Found
- 对于JSONObject,我只是临时抱佛脚
- 总结切面编程AOP的注解式开发和XML式开发
- 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 数组属性和方法
- 关于背包问题的一点发散
- 没有SortedList,如何快速找到中值
- DFS最难也就这样了
- 浅谈二分查找的变种
- BFS(广度优先算法)也就这么回事
- 从零钱兑换再看动态规划的套路
- Azure认知服务之使用墨迹识别功能识别手写汉字
- 基于 TypeScript 的 Weex 优化实践
- R语言数据库中如何多条件排序
- 用好 Java 中的枚举,真的没有那么简单!
- ABAP整型类型的几种位操作 - OR, AND, XOR的
- 【机器学习】算法原理详细推导与实现(七):决策树算法
- 如何使用代码修改SAP CRM One Order CUMULAT_H对象的值
- Caffeine Cache~高性能 Java 本地缓存之王
- 用Python的Pandas和Matplotlib绘制股票唐奇安通道,布林带通道和鳄鱼组线