`
yzmduncan
  • 浏览: 330330 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
文章分类
社区版块
存档分类
最新评论

有向图——强连通分量

阅读更多

    有向图的强连通分量(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. 通过键盘输入图的顶点和边信息,分别构造一个无向图的...

    求强连通分量---模板(K算法)

    在图论中,有向图中的强连通分量是指图中的一个子集,其中任意两个顶点都是相互可达的。求解强连通分量是图论中的一个重要问题,对于理解图的结构具有重要意义。本篇文章将详细介绍如何使用Kosaraju算法来求解有向图...

    算法刷题提高阶段-图论10

    在3.7 有向图的强连通分量(filter).mp4这个视频中,可能详细讲解了如何利用DFS进行强连通分量的检测和分解。 在算法实现上,通常有两种方法: 1. 双向DFS:首先从任意顶点开始进行DFS,标记所有可达的顶点。然后,...

    06 StronglyConnectedComponents.rar

    换句话说,强连通分量是有向图中最大且互相可达的子图。这个概念在分析网络结构、设计复杂算法以及解决许多实际问题时非常有用,例如在路由算法、网络设计、任务调度等领域。 实现强连通分量的算法通常基于深度优先...

    数据结构——图(总结)

    对于有向图,DFS可能无法得到连通的强连通分量,而BFS则可以形成一个强连通分量的生成树。 总之,图作为一种数据结构,能够有效地表示和处理复杂的关系网络。了解其定义、术语、存储和遍历方法是理解并解决许多实际...

    算法导论生成一个100个点3000条边的有向无环图实验1-4

    在有向图中,如果从每个顶点都能通过一系列边到达其他所有顶点,那么这些顶点组成一个强连通分量。在一个DAG中,可能存在多个强连通分量,也可能只有一个大的强连通分量或者完全没有强连通分量。找出这些分量对于...

    Tarjan算法[收集].pdf

    《Tarjan算法——高效求解有向图强连通分量》 Tarjan算法是一种用于求解有向图强连通分量的高效算法,它基于深度优先搜索(DFS)策略,由著名计算机科学家Robert Tarjan提出。在有向图中,如果两个顶点之间存在双向...

    数据结构——图的有关操作

    (1)以邻接表作为图的存储结构,从键盘输入图的顶点与弧的信息建立一个有向图; (2)对(1)中生成的有向图进行深度优先遍历并打印结果; (3)在(1)中生成的有向图中,分别插入与删除一条弧并打印其结果; (4)在(1...

    数据结构——图PPT学习教案.pptx

    对于有向图,强连通图是每个顶点对之间都存在双向路径的图,其最大强连通子图是强连通分量。 在图的操作上,常见的有建立和销毁图结构、插入或删除顶点和边、访问顶点以及遍历图。图的存储结构主要有三种:邻接矩阵...

    图论- 图的连通性.rar

    1. 强连通图:在有向图中,如果对于每对不同的顶点u和v,都存在从u到v的有向路径和从v到u的有向路径,那么这个有向图被称为强连通图。强连通图意味着图中每个顶点都能到达其他所有顶点。 2. 弱连通图:如果将有向图...

    北京师范大学数据结构教学资料第8章——图.ppt

    在有向图中,强连通图是每个顶点都能到达其他任何顶点的图,强连通分量是非强连通图的极大强连通子图。 生成树是连通图的一个重要概念,它是图的一个极小连通子图,包含所有顶点但只有n-1条边(对于n个顶点的图)。...

    山东大学软件学院数据结构课程设计——22.图的实现与分析分别对有向图

    本课程设计聚焦于图的实现与分析,特别是针对有向图。有向图是由顶点和边组成的,其中每条边都有明确的方向,从一个顶点指向另一个顶点。 在Java中,有多种方法可以实现图。一种常见的方式是使用邻接矩阵,这是一个...

    图论- 图的连通性- Tarjan 求双连通分量.rar

    在一个无向图中,如果删除任意一条边都不会导致图变为不连通,那么这个连通分量被称为双连通分量。换句话说,双连通分量中的任意两个顶点都存在至少两条互相独立的路径。双连通分量的研究在诸如网络可靠性、数据结构...

    锦绣育才图的连通性PPT

    - **强连通分量**: 有向图的强连通分量是指图中最大的强连通子图。 - **割点和割边** - **割点**: 对于一个无向图,如果删除一个节点后图的连通分量数增加,则称该节点为割点。 - **割边(桥)**: 如果删除一条边后...

    10 数据结构第六章 图知识点.docx

    * 强连通图:在有向图中,任意两个顶点之间有路径。 * 强连通分量:非强连通图的极大强连通子图。 生成树: * 生成树:n 个顶点的连通图 G 的生成树是包含 G 中全部顶点的一个极小连通子图。 深度优先遍历和广度...

    图——基本概念和类型定义

    有向图 无向图 完全图 稀疏图 稠密图 权 网 邻接 关联(依附) 顶点的度 有向树 路径 路径长度 回路(环) 简单路径 简单回路(简单环) 连通图 强连通图 子图 连通分量 强连通分量 极小连通子图 生成树 生成森林 图...

    数据结构——图的实现

    此外,图还涉及到很多其他算法,如拓扑排序(对于有向无环图,确定一个唯一的顶点顺序),强连通分量(判断有向图中两个顶点是否互相可达),以及二分图检测(检查图是否可以分割为两个互不相交的子集,使得每条边...

    ACM知识点——图论讲解

    6. **强连通分量**:在有向图中,若从顶点u到顶点v以及从v到u都存在路径,则称u和v强连通。找出所有强连通分量是分析有向图结构的关键。 7. **欧拉路径与回路**:欧拉路径是经过图中所有边恰好一次的路径,而欧拉...

    最大分量:调整网络矩阵并输出其最大连通分量中的节点列表-matlab开发

    此外,对于有向图,MATLAB的`conncomp`函数可以用来找出强连通分量,即图中任何节点都可以到达其他所有节点的子图。 在给定的压缩包文件`largestcomponent.zip`中,很可能包含了示例代码、测试数据以及关于如何使用...

Global site tag (gtag.js) - Google Analytics