tarjan缩点相关知识及代码

emmm原谅我确实是找不到不用缩点的tarjan题才会想到自学一下缩点这个东西的。。

题目没有,只能自己出数据并手动模拟。。。

首先看一张图(懒得画,还是看输入数据吧,劳烦自行画图。。)

7 9(n个点,m个关系,以下m行每一行为两个点a,b之间有a指向b的一条有向边)
1 2
2 3
3 1
3 4
4 5
4 7
7 5
6 7
6 5

在画过图之后,显然可知,1 2 3这3个节点在一个强连通分量中(如果不理解强连通分量自行度娘哦),将其缩点,并利用1 2 3结点的边关系将缩成的点与其他点融合,形成新的图。好的,那么只需要套一遍tarjan,将每个强连通分量内的点赋值为该强连通分量的编号,再利用新的链式前向星存储新的图,已达到缩点的功效

 1 #include<set>
 2 #include<map>
 3 #include<list>
 4 #include<queue>
 5 #include<stack>
 6 #include<string>
 7 #include<cmath>
 8 #include<ctime>
 9 #include<vector>
10 #include<bitset>
11 #include<memory>
12 #include<utility>
13 #include<cstdio>
14 #include<sstream>
15 #include<iostream>
16 #include<cstdlib>
17 #include<cstring>
18 #include<algorithm>
19 using namespace std;
20 const int N=100005;
21 
22 stack <int> q;
23 int tot,n,m,num;
24 int head[N],next[N],to[N],head2[N],next2[N],to2[N],dfn[N],low[N],f[N];//后缀为2的记录的是缩点后所得图的信息
25 bool visit[N];
26 
27 inline int mi(int a,int b){return a<b?a:b;}
28 inline int ma(int a,int b){return a>b?a:b;}
29 
30 inline void add(int u,int v){//对读入的数据进行处理
31     next[++tot]=head[u];
32     head[u]=tot;
33     to[tot]=v;
34 }
35 
36 inline void add2(int u,int v){//对缩点后的数据进行处理
37     next2[++tot]=head2[u];
38     head2[u]=tot;
39     to2[tot]=v;
40 }
41 
42 void tarjan(int u){//tarjan板子
43     dfn[u]=low[u]=++tot;
44     visit[u]=1;
45     q.push(u);
46     for(int i=head[u];i;i=next[i]){
47         if(!dfn[to[i]]){
48             tarjan(to[i]);
49             low[u]=mi(low[u],low[to[i]]);
50         }
51         else if(visit[to[i]]){
52             low[u]=mi(low[u],low[to[i]]);
53         }
54     }
55     if(dfn[u]==low[u]){
56         int v;
57         num++;
58         do{
59             v=q.top();
60             q.pop();
61             visit[v]=0;
62             f[v]=num;//记录v节点存在的强连通分量编号
63         }while(v!=u&&!q.empty());
64     }
65 }
66 
67 int main(){
68     scanf("%d%d",&n,&m);
69     for(int i=1;i<=m;i++){
70         int u,v;
71         scanf("%d%d",&u,&v);
72         add(u,v);
73     }
74     tot=0;
75     for(int i=1;i<=n;i++){
76         if(!dfn[i]){
77             tarjan(i);
78         }
79     }
80     tot=0;
81     for(int i=1;i<=n;i++){
82         for(int j=head[i];j;j=next[j]){
83             if(f[i]!=f[to[j]]){//去除在同一强连通分量的节点情况
84                 add2(f[i],f[to[j]]);
85             }
86         }
87     }
88     return 0;
89 }

那着就是缩点了,我个人感觉并不是很困难

posted @ 2019-07-15 11:58  喵呜,颜儿ღ  阅读(109)  评论(0编辑  收藏  举报