有向图传递闭包

摘要:
目录传递闭包的定义有向图的传递闭包是Floydwarshall算法的一个应用。传递闭包定义对于有向图G(V,E),传递闭包是G(V、E),其中E{(i,j):图G包含从i到j}的路径。Floydwarshall传递闭包算法的实现void floyd_warshall(){for{for}{if{mp[i][j]=1;{\f5}很容易知道时间复杂度是O(V^3);DFS传递闭包算法分析DFS时间复杂度为O(V+E);对每个节点使用DFS,我们可以每次获得一个节点的可达节点,并且可以获得有向图的传递闭包。时间复杂度为V*O(V+E),即O;如果图的边数较少,则第二种算法更有效,可以根据主题的数据约束进行选择。

目录

有向图的传递闭包是Floyd warshall 算法的一种应用(主要参考算法导论)

传递闭包的定义

对于有向图G(V,E)的传递闭包即是G(V,E),其中E{(i,j):图G中包含一条由i到j的路径}。

Floyd warshall 传递闭包算法

Floyd warshall 代码

void floyd_warshall()
{
    int tmp;
    for(int k = 1; k <= n; ++k)
    {
        for(int i = 1; i <= n; ++i)
        {
            for(int j = 1; j <= n; ++j)
            {
                //松弛操作; 
                { 
                    tmp = mp[i][k] + mp[k][j];
                    if(tmp < mp[i][j])
                    {
                        mp[i][j] = tmp;
                    }
                }
            }
        }
    }
}

算法实现原理

由于我们只需要确定节点对(i,j)之间是存在i->j的路径,所以,对于松弛操作可以有两种优化方式,
(1)将所有节点对之间的存在的直接连通的边权重设为1,不连通设为INF(无穷大)。然后运行该算法,如果mp[i][j] < n;则(i,j)之间存在一条简单路径。如果mp[i][j] = INF,则两者之间不存在路径。
(2)可以将松弛策略改为,mp[i][j] == 1|| (mp[i][k] ==1 && mp[k][j] == 1)也即是要么,i可以通过{1,2,3,,,k-1}中的部分节点到达j,要么i可以通过{1,2,3,,,k-1}中的部分节点到达j,可以参考对Floyd warshall 算法的分析链接

Floyd warshall 传递闭包算法的实现

void floyd_warshall()
{
	for(int k = 1; k <= n; ++k)
	{
		for(int i = 1; i <= n; ++i)
		{
			for(int j = 1; j <= n; ++j)
			{
				if(mp[i][j] == 1 || mp[i][k] == 1 && mp[k][j] == 1)
				{
					mp[i][j] = 1;
				}
			}
		}
	}
}

时间复杂度

容易知道时间复杂度为O(V^3);

DFS 传递闭包算法

算法分析

DFS时间复杂度为O(V+E);
使用对每个节点进行DFS,每次可以得出一个节点的可以到达的节点,可以求出有向图的传递闭包,时间复杂度为V*O(V+E),即O(V*(V+E)); 
如果图的边数较少时,第二种算法更有效,可以根据题目的数据约束进行选择。

代码实现

int vis[N][N];//vis[i][j]表示i->j可达 
void dfs(int s)//普通的dfs算法
{
	int num = n;
	stack<int> st;
	st.push(s);
	vis[s][s] = 1;
	while(!st.empty())
	{
		int now = st.top();
		st.pop();
		int len = ed[now].size();
		for(int i = 0;i < len; ++i)
		{
			if(vis[s][ed[now][i]] == 0)
			{
				st.push(ed[now][i]);
				vis[s][ed[now][i]] = 1;
			}
		}
	}	
}			

例题

Cow Contest
通信网络可以在CCF csp 官网进行提交练习。

如有错误,恳请指正。

免责声明:文章转载自《有向图传递闭包》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Java学习之二-Java反射机制普通交叉验证(OCV)和广义交叉验证(GCV)下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Groovy 学习手册(5)

8. 函数式编程 函数式编程(FP)是一种编程风格,侧重于函数和最小化状态的变化(使用不可变的数据结构)。它更接近于用数学来表达解决方案,而不是循序渐进的操作。 在函数式编程里,其功能应该是“无副作用”(不会改变外部功能),参考透明的(一个函数每次传递相同的参数,返回相同的值)。 函数式编程可以被看作是一种更常见的命令式编程的替代,它更接近告诉计算机遵循每...

golang闭包和range,关于闭包内使用外部变量

遇到经典问题 func mian() { resslice := []int{1, 2, 3, 4} for _, v := range resslice { fmt.Println(v) defer fun1(v) } } func fun1(value int) { fmt.Println(value) }   输出结果为...

深度优先生成树及其应用

在上一篇博客判断有向图是否有圈中从递归的角度简单感性的介绍了如何修改深度优先搜索来判断一个有向图是否有圈。事实上, 它的实质是利用了深度优先生成树(depth-first spanning tree)的性质。那么什么是深度优先生成树?顾名思义,这颗树由深度优先搜索而生成的,由于无向图与有向图的深度优先生成树有差别,下面将分别介绍。 一. 无向图的深度优先生...

关于lua闭包导致引用无法释放内存泄露

最近项目存在严重的内存泄漏问题,每次切level 会增加20M无法释放的内存,翻遍了项目用了多个工具,查询资料等 发现项目中两种存在内存泄露的情况 1.lua闭包的不当使用,对比包的引用要及时 释放。 2.注册事件未及时取消订阅,注册到C#的luafunction 用完一定要dispose,委托事件要对应取消订阅或清空事件。 lua闭包写法 functio...

[转]C++11中的Lamda

[转载]http://coolshell.cn/articles/5265.html/comment-page-1  Lambda表达式来源于函数式编程,说白就了就是在使用的地方定义函数,有的语言叫“闭包”,如果 lambda 函数没有传回值(例如void),其回返类型可被完全忽略。 定义在与 lambda 函数相同作用域的变量参考也可以被使用。这种的变量...

Swift 内存管理详解

Swift内存管理: Swift 和 OC 用的都是ARC的内存管理机制,它们通过 ARC 可以很好的管理对象的回收,大部分的时候,程序猿无需关心 Swift 对象的回收。 注意: 只有引用类型变量所引用的对象才需要使用引用计数器进行管理,对于枚举、结构体等,他们都是值类型的。因此不需要使用引用计数进行管理。 一:理解ARC 1: ARC 自动统计改对象被...