码迷,mamicode.com
首页 > 其他好文 > 详细

tarjan缩点与割点

时间:2019-09-14 22:44:12      阅读:357      评论:0      收藏:0      [点我收藏+]

标签:||   tar   ima   turn   put   mes   val   else   amp   

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的算法

首先

tarjan缩点与割点

标签:||   tar   ima   turn   put   mes   val   else   amp   

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

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!