好久没得写这些了,之前写的也找不到了,因而我打算利用晚上的时间从头写。一方面是让本身能更透彻的思考问题,顺便练手,另一方面也是和你们有个交流机会。最近一段时间我先会写一些经典算法的理解或者题目解题,好比ACM、一些公司面试题目、平时在工做中容易使用到的,也有机会来进行一些问题的讨论。
若是是题解,我会注明题目的出处,有兴趣能够尝试解题并提交代码。题目解题我会优先选用Python编写,部分不支持Python的Online Judge我选用C++。
限于本身的水平,有错误的地方还请指正python
言归正传,先从一个简单的题目入手:面试
<题目来源:百度2017秋招,http://exercise.acmcoder.com/... >算法
在一个无向图G=(V,E)中,定义顶点s到顶点t的特征距离是构成从顶点s->t的最短路径(shortest path)的边集中E'= {e1,e2...en}中最长的边的大小。目标是要找到这个全部最短路径中最大的特征距离。app
问题比较明确了,最直接的解决问题思路是直接求出s->t的全部最短路径,再遍历全部的最短路径找出最长的边便可。测试
首先考虑选择单源点最短路径算法:
(1)Dijkstra
(2)SPFA优化
该图是一个不含有负权变的无向图,上面两种算法均可以采用,这里选择SPFA,这个算法的算法核心就是对队列中的顶点进行松弛操做:
dist[u] = min{dist[u], dist[v] + edge(u, v).wight}
其实质是若是到达u的最短路径能够由到达顶点v的最短路径加上链接u,v边的权获得,而且比原来的路径更短,那么咱们就能够用这条新的路径长度来更新到达u的最短路径,这样的操做称之为松弛操做。而后咱们在整个图中不断尝试寻找这样的顶点进行松弛操做,直到不能再发现能够松弛的顶点。spa
那么考虑能不能在SPFA松弛获得dist[v]的过程当中记录到达顶点v的最长的边max_edge[v]呢?那么这样在一次SFPA后,在求得最短路径的同时也获得了题目所求的最长的边。code
分析上面的松弛操做后,发现并不容易实现,缘由是,对顶点u的任何一次松弛操做都不能肯定edge(u,v)是否最终在到达u的最短路径中。因为每次须要获取最大的边,须要不断保留最大的那条边。一旦某个边再也不是构成最短路径上的边的时候,那么这个结果就错误了。在松弛过程当中去存储所有路径不是一个明智的选择。orm
咱们在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 heapq const_idx_vertex = 0 const_idx_wight = 1 def 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] = True def 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()