有向图连通分量SCC
2013-12-03 23:51
232 查看
在无向图中,如果从顶点vi到顶点vj有路径,则称vi和vj连通。如果图中任意两个顶点之间都连通,则称该图为连通图,否则,称该图为非连通图,则其中的极大连通子图称为连通分量,这里所谓的极大是指子图中包含的顶点个数极大。
直观地说,极大就是不能再大,或者说再大也不能超过自己。因此,极大连通子图就是:
设
1) S为G的子图,S连通,
2) 如果有S'也是G的连通子图,且S是S'的子图,可推出S = S',
则称S是G的极大连通子图。
极小连通子图正好相反,极小就是不能再小,再多小一点就会不连通或点不足。因此,极小连通子图就是:
设
1) S为G的子图,S连通,
2) 如果有S'也是G的连通子图,S'包含G的所有顶点,且S'是S的子图,可推出S' = S,
则称S是G的级小连通子图。
注:这个定义和pinejeely给出的等价。这里给出的定义比较容易验证。
在有向图中,如果对于每一对顶点vi和vj,从vi到vj和从vj到vi都有路径,则称该图为强连通图;否则,将其中的极大强连通子图称为强连通分量。
Kosaraju算法:先dfs,得到最后完成时间f,再求反图,按f递减的方向对反图再dfs一次。
Tarjan算法只需一次dfs,而且不用求反图,dfs找最早祖先点(最先被发现)也就是寻找B边。
使用LOW函数测试此条件
Gabow算法:思路与tarjan思路一样,但是用一个stack替代了low数组,使得交换次数减小
直观地说,极大就是不能再大,或者说再大也不能超过自己。因此,极大连通子图就是:
设
1) S为G的子图,S连通,
2) 如果有S'也是G的连通子图,且S是S'的子图,可推出S = S',
则称S是G的极大连通子图。
极小连通子图正好相反,极小就是不能再小,再多小一点就会不连通或点不足。因此,极小连通子图就是:
设
1) S为G的子图,S连通,
2) 如果有S'也是G的连通子图,S'包含G的所有顶点,且S'是S的子图,可推出S' = S,
则称S是G的级小连通子图。
注:这个定义和pinejeely给出的等价。这里给出的定义比较容易验证。
在有向图中,如果对于每一对顶点vi和vj,从vi到vj和从vj到vi都有路径,则称该图为强连通图;否则,将其中的极大强连通子图称为强连通分量。
Kosaraju算法:先dfs,得到最后完成时间f,再求反图,按f递减的方向对反图再dfs一次。
#include <stdio.h> #include <string.h> #include <algorithm> #include <iomanip> #include <set> #include <map> #include <vector> #include <queue> using namespace std; #define N 1000 int head , headt , cnt; struct node { int next, to; }edge[N * 2], edget[N * 2]; void addedge(int from, int to)//G_T { cnt++; edge[cnt].next = head[from]; edge[cnt].to = to; head[from] = cnt; //得到反图 edget[cnt].next = headt[to]; edget[cnt].to = from; headt[to] = cnt; } int f ;//finishtime int d ;//discovertime int color ;//init 0 denote white; 1 denote gray discover; 2 denote black finish int time; int belong ;//which scc int cur;//current scc void dfs_visit(int x) { color[x] = 1; d[x] = ++time; int i, j; for (i = head[x]; i; i = edge[i].next) { j = edge[i].to; if (!color[j]) { dfs_visit(j); } } //color[x] = 2; f[x] = ++time; } void dfs_visit_t(int x) { color[x] = 1; //d[x] = ++time; int i, j; for (i = headt[x]; i; i = edget[i].next) { j = edget[i].to; if (!color[j]) { dfs_visit_t(j); } } //color[x] = 2; //f[x] = ++time; belong[x] = cur; } bool cmp(const int &a, const int &b) { return a > b; } map<int, int, greater<int> > mp;//使用map对f[i]进行从大到小排序 map<int, int>::iterator it; void init() { cnt = cur = 1; time = -1; memset(head, 0, sizeof(head)); memset(f, 0, sizeof(f)); memset(d, 0, sizeof(d)); memset(color, 0, sizeof(color)); memset(belong, 0, sizeof(belong)); mp.clear(); } int main() { int n, m, u, v, i; while (~scanf("%d%d", &n, &m)) { init(); for (i = 0; i < m; i++) { scanf("%d%d", &u, &v); addedge(u, v); } for (i = 1; i <= n; i++)//得到f if (!color[i]) dfs_visit(i); //sort(f, f + n, cmp); for (i = 1; i <=n; i++)//对f排序 mp[f[i]] = i; memset(color, 0, sizeof(color)); for (it = mp.begin(); it != mp.end(); ++it)//对反图进行dfs { if (!color[it->second]) { dfs_visit_t(it->second); cur++; } } for (i = 1; i <=n; i++) printf("%d ", belong[i]); } return 0; }
Tarjan算法只需一次dfs,而且不用求反图,dfs找最早祖先点(最先被发现)也就是寻找B边。
使用LOW函数测试此条件
#include <stdio.h> #include <string.h> #include <algorithm> #include <iomanip> #include <set> #include <map> #include <vector> #include <queue> #include <stack> #define INF 0x7fffffff using namespace std; #define N 1000 stack<int> s; int head , cnt; struct node { int next, to; }edge[N * 2]; void addedge(int from, int to) { cnt++; edge[cnt].next = head[from]; edge[cnt].to = to; head[from] = cnt; } //int f ;//finishtime int pre ;//discovertime //int color ;//init 0 denote white; 1 denote gray discover; 2 denote black finish int time; int id ;//which scc int low ;// int cur;//current scc void dfs_visit(int x) { low[x] = pre[x] = ++time; s.push(x); int i, j; for (i = head[x]; i; i = edge[i].next) { j = edge[i].to; if (!pre[j]) { dfs_visit(j); } if (low[j] < low[x])//找最小的low[x],即是否存在后向边(B边) low[x] = low[j]; } if (low[x] == pre[x])//找到了一个scc { do { i = s.top(); s.pop(); low[i] = INF; id[i] = cur; }while (i != x); cur++; } } void init() { cnt = cur = 1; time = 0; memset(head, 0, sizeof(head)); memset(pre, 0, sizeof(pre)); memset(low, 0, sizeof(low)); memset(id, 0, sizeof(id)); while (!s.empty()) s.pop(); } int main() { int n, m, u, v, i; while (~scanf("%d%d", &n, &m)) { init(); for (i = 0; i < m; i++) { scanf("%d%d", &u, &v); addedge(u, v); } for (i = 1; i <= n; i++) if (!pre[i]) dfs_visit(i); for (i = 1; i <=n; i++) printf("%d ", id[i]); } return 0; }
Gabow算法:思路与tarjan思路一样,但是用一个stack替代了low数组,使得交换次数减小
#include <stdio.h> #include <string.h> #include <algorithm> #include <iomanip> #include <set> #include <map> #include <vector> #include <queue> #include <stack> #define INF 0x7fffffff using namespace std; #define N 1000 stack<int> s; stack<int> p; int head , cnt; struct node { int next, to; }edge[N * 2]; void addedge(int from, int to) { cnt++; edge[cnt].next = head[from]; edge[cnt].to = to; head[from] = cnt; } //int f ;//finishtime int pre ;//discovertime //int color ;//init 0 denote white; 1 denote gray discover; 2 denote black finish int time; int id ;//which scc int low ;// int cur;//current scc void dfs_visit(int x) { low[x] = pre[x] = ++time; s.push(x); p.push(x); int i, j; for (i = head[x]; i; i = edge[i].next) { j = edge[i].to; if (!pre[j]) dfs_visit(j); if (!id[j])//该点未在已求的scc中 while (pre[j] < pre[p.top()])存在后向边,出栈 p.pop(); } if (p.top() == x)//找到一个scc { p.pop(); do { i = s.top(); id[i] = cur; s.pop(); }while (i != x); cur++; } } void init() { cnt = cur = 1; time = 0; memset(head, 0, sizeof(head)); memset(pre, 0, sizeof(pre)); memset(low, 0, sizeof(low)); memset(id, 0, sizeof(id)); while (!s.empty()) s.pop(); while (!p.empty()) p.pop(); } int main() { int n, m, u, v, i; while (~scanf("%d%d", &n, &m)) { init(); for (i = 0; i < m; i++) { scanf("%d%d", &u, &v); addedge(u, v); } for (i = 1; i <= n; i++) if (!pre[i]) dfs_visit(i); for (i = 1; i <=n; i++) printf("%d ", id[i]); } return 0; }
相关文章推荐
- 强连通分量scc
- 强连通分量scc
- UVA 11324 有向图强连通分量缩点得SCC图,并在其上求最长路径
- 强连通分量SCC模版(LRJ)
- 有向图的强连通分量的分解 总结 poj2186例题举例
- 【有向图强连通分量(SCC)】
- 强连通分量(SCC)Kosaraju算法学习笔记
- 求解有向图的强连通分量的SCC问题---POJ 2186 Popular Cows
- 有向图强连通分量的Tarjan算法
- 有向图强连通分量的Tarjan算法
- 强连通分量SCC
- 有向图强连通分量的Tarjan算法
- 强连通分量(SCC)模版
- 有向图的强连通分量分解
- poj 1236 scc强连通分量
- 强连通分量(SCC)的Tarjan算法
- HDU1856——最大连通分量的节点个数
- 数据结构实验:连通分量个数
- 【bzoj2438】【中山市选2011】【杀人游戏】【强连通分量缩点】
- The King’s Problem(tarjan求强连通分量缩点+匈牙利求有向无环图的最小路径覆盖)