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 }
那着就是缩点了,我个人感觉并不是很困难