有向图的强连通分量(strongly connected components)
在有向图G中,如果两个顶点vi,vj间(vi!=vj)有一条从vi到vj的路径,同时还有一条从vj到vi的路径(顶点相互可达),则称两个顶点强连通。如果有向图G的每对顶点都强连通,称G是个强连通图。非强连通图有向图的极大强连通子图,称为强连通分量。
求解强连通分量的算法主要有三种:Kosaraju,Tarjan,Gabow。下面介绍Tarjan算法。
Tarjan算法基于图的深度遍历。定义dfn[u]是结点u的时间戳,low[u]为u和u的子树能够追溯到的最早的栈中结点的时间戳。
low[u] = min{dfn[u], low[v](u,v为树枝边,u为v的父节点), dfn[v](u,v为指向栈中结点的后向边)};
当dfn[u] == low[u]时,以u为根的搜索子树上所有结点是一个强连通分量。
关于Tarjan算法的详细介绍,参考:
http://hi.baidu.com/escorter2009/blog/item/f35951dc5bdb3de677c63826.html
POJ2186
题目大意:有n头牛,每头牛都希望自己受欢迎,输入a b表示a认为b受欢迎。要求出受其它所有牛欢迎的牛的个数。
解:首先求强连通分量,分量中每头牛都受分量中其它牛的欢迎。分量之间至多有一条有向边。那么显然需要找出出度为0的强连通分量,若有大于1的出度为0的强连通分量,这两个连通分量互相不认为对方受欢迎,显然个数为0;则有且仅有一个入读度为0的强连通分量时,该强连通分量的结点数即为解。
//出度为0的scc
#include <iostream>
const int MAX = 10002;
int n,m;
int low[MAX],dfn[MAX],seq;
bool inStack[MAX];
struct Edge
{
int to;
int next;
}e[50001];
int index[MAX],edgeNum;
int stack[MAX],top;
int belong[MAX]; //belong[i]表示结点i属于的连通分量
int outdegree[MAX];
int cnt; //cnt为当前强连通分量的标记值
int min(int x, int y)
{
return x < y ? x : y;
}
void addEdge(int from, int to)
{
e[edgeNum].to = to;
e[edgeNum].next = index[from];
index[from] = edgeNum++;
}
void Tarjan(int u)
{
low[u] = dfn[u] = seq++;
stack[top++] = u; //将结点u入栈
inStack[u] = true;
for(int i = index[u]; i != -1; i = e[i].next)
{
int w = e[i].to;
if(dfn[w] < 0)
{
Tarjan(w);
low[u] = min(low[u],low[w]);
}
else if(inStack[w]) //如果节点w还在栈内
low[u] = min(low[u],dfn[w]);
}
if(dfn[u] == low[u]) //u是强连通分量的根
{
int v;
cnt++;
//出栈,缩点
do
{
top--;
v = stack[top];
inStack[v] = false;
belong[v] = cnt;
}while(u != v);
}
}
void solve()
{
int i,j;
for(i = 1; i <= n; i++)
if(dfn[i] < 0)
Tarjan(i);
for(i = 1; i <= n; i++)
{
for(j = index[i]; j != -1; j = e[j].next)
{
if(belong[i] != belong[e[j].to])
outdegree[belong[i]]++;
}
}
int num = 0; //出度为0的连通分量的个数
int who; //哪个连通分量
for(i = 1; i <= cnt; i++)
{
if(outdegree[i] == 0)
{
who = i;
num++;
}
}
if(num != 1)
printf("0\n");
else
{
int result = 0;
for(i = 1; i <= n; i++)
if(belong[i]==who)
result++;
printf("%d\n",result);
}
}
int main()
{
int i,j;
int from,to;
edgeNum = 0;
seq = 0;
top = 0;
cnt = 0;
memset(dfn,-1,sizeof(dfn));
memset(index,-1,sizeof(index));
memset(inStack,0,sizeof(inStack));
memset(outdegree,0,sizeof(outdegree));
scanf("%d %d",&n,&m);
for(i = 0; i < m; i++)
{
scanf("%d %d",&from,&to);
addEdge(from,to);
}
solve();
return 0;
}
POJ2553
题目大意:一个图由结点集v和边集E组成,现在要求出一个点集合:
bottom(G)={v∈V|∀w∈V:(v→w)⇒(w→v)}(对于集合中的任意一点v和V中的任意一点w,如果v能到达w,那么w也能到达v)。
解:首先求强连通分量,联想到出度为0的scc(因为出度不为0的scc,不满足集合的定义)。
//出度为0的所有scc
#include <iostream>
const int MAX = 5005;
int n,m;
struct Edge
{
int to;
int next;
}e[MAX*MAX];
int index[MAX],edgeNum;
int low[MAX],dfn[MAX],seq;
int stack[MAX],top;
bool inStack[MAX];
int belong[MAX],outdegree[MAX],cnt;
int result[MAX],count;
int min(int x, int y)
{
return x < y ? x : y;
}
void addEdge(int from, int to)
{
e[edgeNum].to = to;
e[edgeNum].next = index[from];
index[from] = edgeNum++;
}
void Tarjan(int u)
{
low[u] = dfn[u] = seq++;
stack[top++] = u;
inStack[u] = true;
for(int i = index[u]; i != -1; i = e[i].next)
{
int w = e[i].to;
if(dfn[w] < 0)
{
Tarjan(w);
low[u] = min(low[u],low[w]);
}
else if(inStack[w]) //如果节点w还在栈内
low[u] = min(low[u],dfn[w]);
}
if(low[u] == dfn[u])
{
int v;
cnt++;
do
{
top--;
v = stack[top];
inStack[v] = false;
belong[v] = cnt;
}while(u != v);
}
}
void solve()
{
int i,j;
for(i = 1; i <= n; i++)
if(dfn[i] < 0)
Tarjan(i);
for(i = 1; i <= n; i++)
{
for(j = index[i]; j != -1; j = e[j].next)
{
if(belong[i] != belong[e[j].to])
outdegree[belong[i]]++;
}
}
for(i = 1; i <= n; i++)
{
if(outdegree[belong[i]] == 0)
result[count++] = i;
}
}
int main()
{
int i,j;
int from,to;
while(true)
{
scanf("%d",&n);
if(n==0)
break;
edgeNum = top = seq = count = cnt =0;
memset(dfn,-1,sizeof(dfn));
memset(index,-1,sizeof(index));
memset(inStack,0,sizeof(inStack));
memset(belong,0,sizeof(belong));
memset(outdegree,0,sizeof(outdegree));
scanf("%d",&m);
for(i = 0; i < m; i++)
{
scanf("%d %d",&from,&to);
addEdge(from,to);
}
solve();
if(count == 0)
printf("\n");
else
{
for(i = 0; i < count-1; i++)
printf("%d ",result[i]);
printf("%d\n",result[i]);
}
}
return 0;
}
分享到:
相关推荐
要求采用邻接矩阵作为无向图的存储结构,邻接表作为有向图的存储结构,完成无向图和有向图的建立,并对建立好的图进行深度和广度优先遍历。具体实现要求: 1. 通过键盘输入图的顶点和边信息,分别构造一个无向图的...
在图论中,有向图中的强连通分量是指图中的一个子集,其中任意两个顶点都是相互可达的。求解强连通分量是图论中的一个重要问题,对于理解图的结构具有重要意义。本篇文章将详细介绍如何使用Kosaraju算法来求解有向图...
在3.7 有向图的强连通分量(filter).mp4这个视频中,可能详细讲解了如何利用DFS进行强连通分量的检测和分解。 在算法实现上,通常有两种方法: 1. 双向DFS:首先从任意顶点开始进行DFS,标记所有可达的顶点。然后,...
换句话说,强连通分量是有向图中最大且互相可达的子图。这个概念在分析网络结构、设计复杂算法以及解决许多实际问题时非常有用,例如在路由算法、网络设计、任务调度等领域。 实现强连通分量的算法通常基于深度优先...
对于有向图,DFS可能无法得到连通的强连通分量,而BFS则可以形成一个强连通分量的生成树。 总之,图作为一种数据结构,能够有效地表示和处理复杂的关系网络。了解其定义、术语、存储和遍历方法是理解并解决许多实际...
在有向图中,如果从每个顶点都能通过一系列边到达其他所有顶点,那么这些顶点组成一个强连通分量。在一个DAG中,可能存在多个强连通分量,也可能只有一个大的强连通分量或者完全没有强连通分量。找出这些分量对于...
《Tarjan算法——高效求解有向图强连通分量》 Tarjan算法是一种用于求解有向图强连通分量的高效算法,它基于深度优先搜索(DFS)策略,由著名计算机科学家Robert Tarjan提出。在有向图中,如果两个顶点之间存在双向...
(1)以邻接表作为图的存储结构,从键盘输入图的顶点与弧的信息建立一个有向图; (2)对(1)中生成的有向图进行深度优先遍历并打印结果; (3)在(1)中生成的有向图中,分别插入与删除一条弧并打印其结果; (4)在(1...
对于有向图,强连通图是每个顶点对之间都存在双向路径的图,其最大强连通子图是强连通分量。 在图的操作上,常见的有建立和销毁图结构、插入或删除顶点和边、访问顶点以及遍历图。图的存储结构主要有三种:邻接矩阵...
1. 强连通图:在有向图中,如果对于每对不同的顶点u和v,都存在从u到v的有向路径和从v到u的有向路径,那么这个有向图被称为强连通图。强连通图意味着图中每个顶点都能到达其他所有顶点。 2. 弱连通图:如果将有向图...
在有向图中,强连通图是每个顶点都能到达其他任何顶点的图,强连通分量是非强连通图的极大强连通子图。 生成树是连通图的一个重要概念,它是图的一个极小连通子图,包含所有顶点但只有n-1条边(对于n个顶点的图)。...
本课程设计聚焦于图的实现与分析,特别是针对有向图。有向图是由顶点和边组成的,其中每条边都有明确的方向,从一个顶点指向另一个顶点。 在Java中,有多种方法可以实现图。一种常见的方式是使用邻接矩阵,这是一个...
在一个无向图中,如果删除任意一条边都不会导致图变为不连通,那么这个连通分量被称为双连通分量。换句话说,双连通分量中的任意两个顶点都存在至少两条互相独立的路径。双连通分量的研究在诸如网络可靠性、数据结构...
- **强连通分量**: 有向图的强连通分量是指图中最大的强连通子图。 - **割点和割边** - **割点**: 对于一个无向图,如果删除一个节点后图的连通分量数增加,则称该节点为割点。 - **割边(桥)**: 如果删除一条边后...
* 强连通图:在有向图中,任意两个顶点之间有路径。 * 强连通分量:非强连通图的极大强连通子图。 生成树: * 生成树:n 个顶点的连通图 G 的生成树是包含 G 中全部顶点的一个极小连通子图。 深度优先遍历和广度...
有向图 无向图 完全图 稀疏图 稠密图 权 网 邻接 关联(依附) 顶点的度 有向树 路径 路径长度 回路(环) 简单路径 简单回路(简单环) 连通图 强连通图 子图 连通分量 强连通分量 极小连通子图 生成树 生成森林 图...
此外,图还涉及到很多其他算法,如拓扑排序(对于有向无环图,确定一个唯一的顶点顺序),强连通分量(判断有向图中两个顶点是否互相可达),以及二分图检测(检查图是否可以分割为两个互不相交的子集,使得每条边...
6. **强连通分量**:在有向图中,若从顶点u到顶点v以及从v到u都存在路径,则称u和v强连通。找出所有强连通分量是分析有向图结构的关键。 7. **欧拉路径与回路**:欧拉路径是经过图中所有边恰好一次的路径,而欧拉...
此外,对于有向图,MATLAB的`conncomp`函数可以用来找出强连通分量,即图中任何节点都可以到达其他所有节点的子图。 在给定的压缩包文件`largestcomponent.zip`中,很可能包含了示例代码、测试数据以及关于如何使用...