博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
今天开始啦,先从一个简单的图论问题入手
阅读量:5876 次
发布时间:2019-06-19

本文共 4611 字,大约阅读时间需要 15 分钟。

很久没得写这些了,以前写的也找不到了,于是我打算利用晚上的时间从头写。一方面是让自己能更透彻的思考问题,顺便练手,另外一方面也是和大家有个交流机会。最近一段时间我先会写一些经典算法的理解或者题目解题,比如ACM、一些公司面试题目、平时在工作中容易使用到的,也有机会来进行一些问题的讨论。

如果是题解,我会注明题目的出处,有兴趣可以尝试解题并提交代码。题目解题我会优先选用Python编写,部分不支持Python的Online Judge我选用C++。
限于自己的水平,有错误的地方还请指正


言归正传,先从一个简单的题目入手:

特征距离

<题目来源:百度2017秋招, >

问题描述:

在一个无向图G=(V,E)中,定义顶点s到顶点t的特征距离是构成从顶点s->t的最短路径(shortest path)的边集中E'= {e1,e2...en}中最长的边的大小。目标是要找到这个所有最短路径中最大的特征距离。

问题比较明确了,最直接的解决问题思路是直接求出s->t的所有最短路径,再遍历所有的最短路径找出最长的边即可。

首先考虑选择单源点最短路径算法:

(1)Dijkstra
(2)SPFA

该图是一个不含有负权变的无向图,上面两种算法都可以采用,这里选择SPFA,这个算法的算法核心就是对队列中的顶点进行松弛操作:

dist[u] = min{dist[u], dist[v] + edge(u, v).wight}
其实质是如果到达u的最短路径可以由到达顶点v的最短路径加上连接u,v边的权得到,并且比原来的路径更短,那么我们就可以用这条新的路径长度来更新到达u的最短路径,这样的操作称之为松弛操作。然后我们在整个图中不断尝试寻找这样的顶点进行松弛操作,直到不能再发现可以松弛的顶点。

那么考虑能不能在SPFA松弛得到dist[v]的过程中记录到达顶点v的最长的边max_edge[v]呢?那么这样在一次SFPA后,在求得最短路径的同时也得到了题目所求的最长的边。

分析上面的松弛操作后,发现并不容易实现,原因是,对顶点u的任何一次松弛操作都不能确定edge(u,v)是否最终在到达u的最短路径中。由于每次需要获取最大的边,需要不断保留最大的那条边。一旦某个边不再是构成最短路径上的边的时候,那么这个结果就错误了。在松弛过程中去存储全部路径不是一个明智的选择。

我们在SPFA结束后,根据dist[]可以求出所有的最短路径

如果dist[u] == dist[v] + edge(u, v),那么v必然是从源点到u的最短路径上的一个点。问题就似乎变得比较简单,我们可以从源点开始,来一个DFS,只需要是满足上面这个表达式的边,我们就对其进行扩展,再深搜这个边连接的顶点。当顶点搜索到我们的终点时,就获得一条从s->t的最路径,当DFS结束后可以获得所有路径。那么只需要找出其他最大的就是答案,如果不可达,直接输出No answer

问题至此已经得到解决,使用python提交,1513ms,感觉速度慢了一些

分析了下,可能是最后在DFS所有的最短路径的时候消耗了比较多的时间

由于我们并不关心具体的最短路径,也不关心这样的最短路径有多少条,而是只关心其中的最长的那条边,而这条边必然是所有边中的一条,遂想到枚举所有的边,然后测试该边是否在最短路径中,仍然需要使用dist[u] == dist[v] + edge(u, v)这个条件,但是,如果确定edge(u, v)就在到t的最短路径中呢?

考虑连结这条边的两个顶点u,v,如果dist[s->u] + edge(u, v).wight + dist[v->t]=dist[s->t]的话,显然edge(u,v)这边边在s->t的最短路径中

其中dist[s->u]就是dist[u],edge(u, v)已知,dist[s->t]就是dist[t],由于我们所求出的dist都是以s作为源点的,而dist[v->t]需要以v为源点,并且每次枚举不同的顶点v'都需要计算不同的dist[v'->t],显然行不通,但是我们也发现一个特点是,我们每次都是计算终点为t的最短路径,如果我们把终点t作为源点,把所有边反向做一次SPFA,就只需要计算一次,就可以得到所有的dist[v'->t],本题是个无向图,处理起来更方便

后面提交,发现效率并没有显著提升,又改为SPFA+heap的方式,仍然没有提高,怀疑是我采用的python的输入方式所导致,中午休息的时候顺手拍了一个CPP的版的,并没有使用heap,然后只需要12ms,可见差距还是比较大。

图片描述

下面是最后采用SPFA+heap优化的代码,DFS和枚举边的方式都有写:

import heapqconst_idx_vertex = 0const_idx_wight = 1def dfs(u, t, vertexes, dist, path, edge_l, res):    if u == t:        #print path        r = 0        for l in edge_l:            r = max(r, l)        res.append(r)        return    for vertex in vertexes[u]:        v = vertex[const_idx_vertex]        w = vertex[const_idx_wight]        if dist[u] + w == dist[v]:            path.append(v)            edge_l.append(w)            dfs(v, t, vertexes, dist, path, edge_l, res)            path.pop()            edge_l.pop()def spfa(dist, src, n, vertexes):    que = []    in_que = [False for i in range(n + 1)]    que.append(src)    in_que[src] = True    dist[src] = 0    heap = []    heapq.heappush(heap, (0, src))    while len(heap) > 0:        info = heapq.heappop(heap)        u = info[1]        in_que[u] = False        for vertex in vertexes[u]:            v = vertex[const_idx_vertex]            w = vertex[const_idx_wight]            if dist[v] > dist[u] + w or dist[v] < 0:                dist[v] = dist[u] + w                if not in_que[v]:                    heapq.heappush(heap, (dist[v], v))                    in_que[v] = Truedef get_max_edge(dist, dist_rev, vertexes, t, n):    ans = -1    for u in range(1, n + 1):        for vertex in vertexes[u]:            v = vertex[const_idx_vertex]            w = vertex[const_idx_wight]            if dist[u] != -1 and dist_rev[v] != -1 and dist[u] + w + dist_rev[v] == dist[t]:                ans = max(ans, w)    return ans if ans > 0 else "No answer"def main():    t_cases = int(raw_input())    for t_case in range(t_cases):        temp = raw_input().split(' ')        n = int(temp[0])        m = int(temp[1])        s = int(temp[2])        t = int(temp[3])        vertexes = [[] for i in range(n + 1)]        for i in range(m):            temp = raw_input().split(' ')            u = int(temp[0])            v = int(temp[1])            w = int(temp[2])            vertexes[u].append([v, w])            vertexes[v].append([u, w])        dist = [-1 for i in range(n + 1)]        '''        # Before improved the code        res = []        path = [s]        edge_l = []        ans = -1        spfa(dist, s, n, vertexes)        if dist[t] > 0:            dfs(s, t, vertexes, dist, path, edge_l, res)            for re in res:                ans = max(re, ans)        if ans < 0:            ans = 'No answer'        print 'Case #{}: {}'.format(t_case + 1, ans)        '''        dist_rev = [-1 for i in range(n + 1)]        spfa(dist, s, n, vertexes)        spfa(dist_rev, t, n, vertexes)        print 'Case #{}: {}'.format(t_case + 1, get_max_edge(dist, dist_rev, vertexes, t, n))if __name__ == '__main__':    main()

转载地址:http://mpkix.baihongyu.com/

你可能感兴趣的文章
远程协助
查看>>
Scrum实施日记 - 一切从零开始
查看>>
关于存储过程实例
查看>>
配置错误定义了重复的“system.web.extensions/scripting/scriptResourceHandler” 解决办法...
查看>>
AIX 7.1 install python
查看>>
PHP盛宴——经常使用函数集锦
查看>>
重写 Ext.form.field 扩展功能
查看>>
Linux下的搜索查找命令的详解(locate)
查看>>
福利丨所有AI安全的讲座里,这可能是最实用的一场
查看>>
开发完第一版前端性能监控系统后的总结(无代码)
查看>>
Python多版本情况下四种快速进入交互式命令行的操作技巧
查看>>
MySQL查询优化
查看>>
【Redis源码分析】如何在Redis中查找大key
查看>>
关于链接文件的探讨
查看>>
android app启动过程(转)
查看>>
Linux—源码包安装
查看>>
JDK8中ArrayList的工作原理剖析
查看>>
安装gulp及相关插件
查看>>
如何在Linux用chmod来修改所有子目录中的文件属性?
查看>>
Applet
查看>>