tarjan缩点与割点

Tarjan算法

先是废话时间:说来挺惭愧 , 好几个月以前就学过tarjan算法然而现在才第一次写

模板题:[luogu P3387]【模板】缩点

tarjan缩点&dp

为啥要缩点答案显然

把环缩成一个点

然后图上拓扑dp



tarjan同名算法有很多 , 比如本blog的缩点与割点的tarjan算法其实并不是一个东西 , 但是很是相似

这个tarjan , 需要三个东西

第一:一个栈来存放搜到的点

第二:一个时间戳dfn , 表示第几个搜到这个点的

第三:low数组 , 表示够追溯到的最早的栈中节点的次序号

首先 , 初始化的时候肯定有

1 dfn[now] = low[now] = ++Index

然后开始遍历边

如果遍历到的点没有碰过

那么递归tarjan

递归结束后

1 low[now] = std::min(low[now], low[to]);

那么如果下一个点已经去过了呐

那么就不用递归了

1 low[now] = std::min(low[now], dfn[to]);

为什么是dfn呢?

照我的理解 , 应该是如果直接用low说不定会跳到这个环以外的地方

不过这个缩点tarjan里面把dfn换成low是可以的 , 但是一会的割点tarjan就不可以了

当最后时一个点的low == dfn , 那个这个点注定是一个缩点之后仍然存留在图上的一个点

那么就可以快落缩点了 , 把栈里的元素不停的向外弹就是了

然后根据题目性质拓扑dp , 没了

  1 #include<cmath>
  2 #include<queue>
  3 #include<stack>
  4 #include<cstdio>
  5 #include<cstring>
  6 #include<cstdlib>
  7 #include<iostream>
  8 #include<algorithm>
  9 #define APART puts("----------------------")
 10 #define debug 1
 11 #define FILETEST 0
 12 #define inf 100010
 13 #define ll long long
 14 #define ha 998244353
 15 #define INF 0x7fffffff
 16 #define INF_T 9223372036854775807
 17 #define DEBUG printf("%s %d\n",__FUNCTION__,__LINE__)
 18
 19 namespace chino{
 20
 21 inline void setting(){
 22 #if FILETEST
 23     freopen("test.in", "r", stdin);
 24     freopen("test.me.out", "w", stdout);
 25 #endif
 26     return;
 27 }
 28
 29 inline int read(){
 30     char c = getchar(), up = c; int num = 0;
 31     for(; c < ‘0‘ || c > ‘9‘; up = c, c = getchar());
 32     for(; c >= ‘0‘ && c <= ‘9‘; num = (num << 3) + (num << 1) + (c ^ ‘0‘), c = getchar());
 33     return  up == ‘-‘ ? -num : num;
 34 }
 35
 36 int n, m;
 37 int ans;
 38 int cntE, cntR, cntJ;
 39 int val[inf], dp[inf];
 40 int vis[inf], in[inf];
 41 int belong[inf], dfn[inf], low[inf];
 42 int head[inf], rehead[inf];
 43 struct Edge{
 44     int to;
 45     int from;
 46     int next;
 47 }e[inf << 1], r[inf << 1];
 48 std::queue <int> Q;
 49 std::stack <int> S;
 50
 51 inline void AddEdge(int from, int to, int &cntE, int *head, Edge *e){
 52     ++cntE;
 53     e[cntE].from = from;
 54     e[cntE].to = to;
 55     e[cntE].next = head[from];
 56     head[from] = cntE;
 57     return;
 58 }
 59
 60 void tarjan(int now){
 61     low[now] = dfn[now] = ++cntJ;
 62     vis[now] = 1;
 63     S.push(now);
 64     for(int i = head[now]; i; i = e[i].next){
 65         int to = e[i].to;
 66         if(dfn[to] == 0){
 67             tarjan(to);
 68             low[now] = std::min(low[now], low[to]);
 69         } else if(vis[to])
 70             low[now] = std::min(low[now], dfn[to]);
 71     }
 72     if(low[now] == dfn[now]){
 73         int top = S.top();
 74         while(1){
 75             top = S.top();
 76             S.pop();
 77             belong[top] = now;
 78             vis[top] = 0;
 79             if(top == now)
 80                 break;
 81             val[now] += val[top];
 82         }
 83     }
 84     return;
 85 }
 86
 87 inline void topoDP(){
 88     while(!Q.empty())
 89         Q.pop();
 90     for(int i = 1; i <= n; i++){
 91         if(belong[i] == i && in[i] == 0)
 92             Q.push(i), dp[i] = val[i];
 93     }
 94     while(!Q.empty()){
 95         int x = Q.front();
 96         Q.pop();
 97         for(int i = rehead[x]; i; i = r[i].next){
 98             int to = r[i].to;
 99             dp[to] = std::max(dp[to], dp[x] + val[to]);
100             --in[to];
101             if(in[to] == 0)
102                 Q.push(to);
103         }
104     }
105     return;
106 }
107
108 inline int main(){
109     n = read();
110     m = read();
111     for(int i = 1; i <= n; i++)
112         val[i] = read();
113     for(int i = 1; i <= m; i++){
114         int u = read();
115         int v = read();
116         AddEdge(u, v, cntE, head, e);
117     }
118     for(int i = 1; i <= n; i++){
119         if(dfn[i] == 0)
120             tarjan(i);
121     }
122     for(int i = 1; i <= m; i++){
123         int u = belong[e[i].from];
124         int v = belong[e[i].to];
125         if(u == v)
126             continue;
127         AddEdge(u, v, cntR, rehead, r);
128         ++in[v];
129     }
130     topoDP();
131     for(int i = 1; i <= n; i++)
132         ans = std::max(ans, dp[i]);
133     printf("%d\n", ans);
134     return 0;
135 }
136
137 }//namespace chino
138
139 int main(){return chino::main();}

复杂度O(n+m)



下一题:P3388 【模板】割点(割顶)

说在前面 , 这道题是无向边 , 上一题是有向边

而割点的定义是:

在无向连通图中,如果将其中一个点以及所有连接该点的边去掉,图就不再连通,那么这个点就叫做割点(cut vertex / articulation point)。

举例 , 这张图5点就是割点

求割点, 也是一个叫做tarjan的算法

首先

原文地址:https://www.cnblogs.com/chiarochinoful/p/algorithm-tarjan.html

时间: 2024-08-29 09:16:40

tarjan缩点与割点的相关文章

tarjan算法(强连通分量 + 强连通分量缩点 + 桥 + 割点 + LCA)

这篇文章是从网络上总结各方经验 以及 自己找的一些例题的算法模板,主要是用于自己的日后的模板总结以后防失忆常看看的, 写的也是自己能看懂即可. tarjan算法的功能很强大, 可以用来求解强连通分量,缩点,桥,割点,LCA等,日后写到相应的模板题我就会放上来. 1.强连通分量(分量中是任意两点间都可以互相到达) 按照深度优先遍历的方式遍历这张图. 遍历当前节点所出的所有边.在遍历过程中: ( 1 ) 如果当前边的终点还没有访问过,访问. 回溯回来之后比较当前节点的low值和终点的low值.将较小

图论 —— tarjan 缩点 割点 (学习历程)

首先,从模板题开始学起—— P3387 [模板]缩点 思路: 1. 这道题为什么要 缩点?(什么时候需要缩点) 根据题目意思,我们只需要找出一条点权最大的路径就行了,不限制点的个数.那么考虑对于一个环上的点被选择了,一整条环是不是应该都被选择,这一定很优,能选干嘛不选.很关键的是题目还允许我们重复经过某条边或者某个点,我们就不需要考虑其他了.因此整个环实际上可以看成一个点(选了其中一个点就应该选其他的点) ——摘录自洛谷第一篇题解 2. 将强连通分量缩点 ->  建边成为DAG -> DPma

【BZOJ-1924】所驼门王的宝藏 Tarjan缩点(+拓扑排序) + 拓扑图DP

1924: [Sdoi2010]所驼门王的宝藏 Time Limit: 5 Sec  Memory Limit: 128 MBSubmit: 787  Solved: 318[Submit][Status][Discuss] Description Input 第一行给出三个正整数 N, R, C. 以下 N 行,每行给出一扇传送门的信息,包含三个正整数xi, yi, Ti,表示该传送门设在位于第 xi行第yi列的藏宝宫室,类型为 Ti.Ti是一个1~3间的整数, 1表示可以传送到第 xi行任意

【BZOJ-1797】Mincut 最小割 最大流 + Tarjan + 缩点

1797: [Ahoi2009]Mincut 最小割 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1685  Solved: 724[Submit][Status][Discuss] Description A,B两个国家正在交战,其中A国的物资运输网中有N个中转站,M条单向道路.设其中第i (1≤i≤M)条道路连接了vi,ui两个中转站,那么中转站vi可以通过该道路到达ui中转站,如果切断这条道路,需要代价ci.现在B国想找出一个路径切断方案

[BZOJ 1051][HAOI 2006]受欢迎的牛(tarjan缩点)

http://www.lydsy.com:808/JudgeOnline/problem.php?id=1051 唔...这题好像在POJ上见过? 比较水的题,很好想出思路.牛和牛之间的关系就像有向图,牛a喜欢牛b相当于建立有向边a->b,然后在这个有向图中,每个强连通分量里的牛们相当于是相互喜欢的,把这个图缩点成DAG,DAG里如果有且仅有一个出度为0的点,则这个点对应强连通分量里的所有牛都是受欢迎的牛,如果没有出度为0的点,当然就没受欢迎的牛了,如果出度为0的点的个数大于1,则每个出度为0的

tarjan缩点以及链式前向星的基本+应用(洛谷1262 间谍网络)

题目描述 由于外国间谍的大量渗入,国家安全正处于高度的危机之中.如果A间谍手中掌握着关于B间谍的犯罪证据,则称A可以揭发B.有些间谍收受贿赂,只要给他们一定数量的美元,他们就愿意交出手中掌握的全部情报.所以,如果我们能够收买一些间谍的话,我们就可能控制间谍网中的每一分子.因为一旦我们逮捕了一个间谍,他手中掌握的情报都将归我们所有,这样就有可能逮捕新的间谍,掌握新的情报. 我们的反间谍机关提供了一份资料,色括所有已知的受贿的间谍,以及他们愿意收受的具体数额.同时我们还知道哪些间谍手中具体掌握了哪些

【BZOJ-2438】杀人游戏 Tarjan + 缩点 + 概率

2438: [中山市选2011]杀人游戏 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1638  Solved: 433[Submit][Status][Discuss] Description 一位冷血的杀手潜入 Na-wiat,并假装成平民.警察希望能在 N 个人里面,查出谁是杀手. 警察能够对每一个人进行查证,假如查证的对象是平民,他会告诉警察,他认识的人, 谁是杀手, 谁是平民. 假如查证的对象是杀手, 杀手将会把警察干掉. 现在警察掌

UVA11504- Dominos(Tarjan+缩点)

题目链接 题意:多米诺骨牌的游戏,给出一些牌,以及哪张牌倒了之后会推倒哪张牌,求最少的推倒牌的张数,使得所有牌都倒下去. 思路:有向图的强连通分量,用Tarjan缩点之后找出入度为0的点的个数,即为答案. 代码: #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int MAXN = 100100;

UVA 11324.The Largest Clique tarjan缩点+拓扑dp

题目链接:https://vjudge.net/problem/UVA-11324 题意:求一个有向图中结点数最大的结点集,使得该结点集中任意两个结点u和v满足:要目u可以到达v,要么v可以到达u(相互可达也可以). 思路:同一个强联通分量中满足结点集中任意两个结点u和v满足:要目u可以到达v,要么v可以到达u(相互可达也可以).把强联通分量收缩点后得到scc图,让每个scc结点的权值等于他的结点数,则求scc图上权最大的路径.拓扑dp,也可以直接bfs,但是要建立一个新的起点,连接所有入度为0