图论
来源:互联网 发布:装修 方面 vr 软件 编辑:程序博客网 时间:2024/06/03 04:08
图论
使用邻接表和邻接矩阵中的邻接矩阵描述
图的遍历
图例如下, 0为起点.
0
/ \
1 2
\ / \
3 4
深度优先搜索(DFS)
python code
N = 5G = [ [ 0, 1, 1, 0, 0 ], [ 1, 0, 0, 1, 0 ], [ 1, 0, 0, 1, 1 ], [ 0, 1, 1, 0, 0 ], [ 0, 0, 1, 0, 0 ]]V = [False for i in range(N)]def dfs(n): print(n) for j in range(N): if not V[j] and G[n][j]: V[j] = True dfs(j)V[0] = Truedfs(0)
广度优先搜索(BFS)
python code
from queue import QueueN = 5G = [ [ 0, 1, 1, 0, 0 ], [ 1, 0, 0, 1, 0 ], [ 1, 0, 0, 1, 1 ], [ 0, 1, 1, 0, 0 ], [ 0, 0, 1, 0, 0 ]]V = [False for i in range(N)]Q = Queue()def bfs(n): Q.put(n) V[0] = True while not Q.empty(): i = Q.get() print(i) for j in range(N): if not V[j] and G[i][j]: Q.put(j) V[j] = Truebfs(0)
最小生成树
问题: 将一个图的所有顶点构成树, 要求边的权值和最小.
普里姆算法:从起点开始选择边, 每次添加一个顶点(边权值和最小)并调整已添加好的顶点集与其他顶点的最短距离(边权值最小), 递归此步骤.
克鲁斯卡尔算法:每次选择最短边, 如果构成环, 则放弃这条边, 递归此步骤.
普里姆(prim)算法
python code
X = 100N = 6G = [ [ X, 6, 1, 5, X, X ], [ 6, X, 5, X, 3, X ], [ 1, 5, X, 1, 5, 4 ], [ 5, X, 1, X, X, 2 ], [ X, 3, 5, X, X, 6 ], [ X, X, 4, 2, 6, X ]]class Edge: def __init__(self, begin, end, lens): self.begin, self.end = begin, end self.lens = lens def __len__(self): return self.lens# init edge infoE = []for i in range(1, N): E.append(Edge(0, i, G[0][i]))# set kth edgefor k in range(0, N-1): # find shortest edge minz, idx = X, -1 for i in range(k, N-1): if len(E[i]) < minz: minz = len(E[i]) idx = i # swap edge E[k], E[idx] = E[idx], E[k] v = E[k].end # adjust edge for i in range(k+1, N-1): d = G[v][E[i].end] if d < len(E[i]): E[i].lens = d E[i].begin = vfor item in E: print(item.begin, item.end, len(item))
克鲁斯卡尔(kruskal)算法
查找是否在相同集合来避免产生环, 集合为存放后继的顶点链.
python code
X = 100N = 6G = [ [ X, 6, 1, 5, X, X ], [ 6, X, 5, X, 3, X ], [ 1, 5, X, 1, 5, 4 ], [ 5, X, 1, X, X, 2 ], [ X, 3, 5, X, X, 6 ], [ X, X, 4, 2, 6, X ]]class Edge: def __init__(self, begin, end, lens): self.begin, self.end = begin, end self.lens = lens def __len__(self): return self.lens# init edge infoE = []for i in range(N): for j in range(i+1, N): if G[i][j] != X: E.append(Edge(i, j, G[i][j]))E.sort(key=lambda x: x.lens)P = [0 for i in range(N)]# save next vertexdef find_set(f): while P[f] > 0: f = P[f] return f# set kth edgecnt_edge = 0for i in range(len(E)): # find set n = find_set(E[i].begin) m = find_set(E[i].end) # if no circle if n != m: # add next vertex for vertex n P[n] = m print(E[i].begin, E[i].end, len(E[i])) # N-1 edges finish cnt_edge += 1 if cnt_edge == N-1: break
最短路径
问题: 计算一个顶点到其他所有顶点的最短路径.
迪杰斯特拉算法: 设置一个起点, 先确定一个最短路径顶点v(第一次确定是相邻的顶点), 再将v作为中间点, 调整起点与各顶点的距离, 递归此步骤.
迪杰斯特拉(dijkstra)算法
INF = 400N = 5G = [ [ 0, 10, INF, 30, 100 ], [ INF, 0, 50, INF, INF ], [ INF, INF, 0, INF, 10 ], [ INF, INF, 20, 0, 60 ], [ INF, INF, INF, INF, 0 ]]# init S & D & P# S(Set for Vertex)# D(Distance for vertex 0 to others)# P(Prev vertex for vertex)S, D, P = [], [], []S.append(0)for i in range(N): D.append(G[0][i]) P.append(0)# set kth vertexfor k in range(1, N): # select shortest edge minz = INF for i in range(N): if not i in S: if D[i] < minz: minz = D[i] v = i # add new vertex to S S.append(v) # adjust D(distance) for i in range(N): if not i in S: if D[i] > D[v]+G[v][i]: D[i] = D[v]+G[v][i] P[i] = v# show shortest distanceprint(D)# show shortest pathfor i in range(1, N): prev = P[i] print(i, end='') while prev != 0: print('<--%d' % prev, end='') prev = P[prev] print('<--%d' % 0)
网络流
二分图匹配问题
问题: 求二分图的最大边匹配(最小点覆盖).
匈牙利算法: 依次匹配, 遇到点已经被匹配的情况下, 尝试能否让被匹配的点的对点匹配其他点(寻找增广路径), 递归此步骤.
二分图待配对情况:
0 <=> 0, 1
1 <=> 1, 2
2 <=> 0
3 <=> 2
匈牙利(Hungary)算法
python code
N = 4G = [ [ 1, 0, 1, 0 ], [ 1, 1, 1, 0 ], [ 0, 1, 0, 1 ], [ 0, 0, 0, 0 ]]R = [-1 for i in range(N)]def find_path(n): for j in range(N): if not V[j] and G[n][j]: V[j] = True if R[j]==(-1) or find_path(R[j]): R[j] = n return True return Falsecnt = 0for i in range(N): V = [False for i in range(N)] if find_path(i): cnt += 1print(cnt)for i in range(N): if R[i] != (-1): print('%d <==> %d' % (i, R[i]))
最大流问题
问题: 起点s, 终点t, 途中经过的管道(边)都有一个最大流量, s到t的最大水流量是多少?
定义: 残量网络 => 当前管道还可以容纳的水量(随着搜索变化), 加入反向边, 如果寻找到的增广路是错误路径, 可以通过反向边修正.
增广路算法: BFS找最短的增广路径, 修改这条路径流量值(修改残量网络边权), 递归此步骤.
增广路(Ford-Fulkerson)算法
python code
import copyfrom queue import QueueINF = 400N = 6G = [ [ 0, 5, 5, 0, 0, 0], [ 0, 0, 0, 5, 5, 0], [ 0, 0, 0, 5, 0, 0], [ 0, 0, 0, 0, 0, 5], [ 0, 0, 0, 0, 0, 5], [ 0, 0, 0, 0, 0, 0]]def find_path(R, P): V = [False for i in range(N)] Q = Queue() Q.put(S) V[S] = True # BFS find_path while not Q.empty(): top = Q.get() for i in range(N): if not V[i] and R[top][i]>0: Q.put(i) V[i] = True P[i] = top # if find vertex T return V[T] == Truedef FF(): # R => Rest Flow Graph(Use Reverse R) R = copy.deepcopy(G) max_flow = 0 # P => Path Of Flow P = [0 for i in range(N)] # if has path while find_path(R, P): min_flow = INF # find min flow v = T while v != S: u = P[v] min_flow = min(min_flow, R[u][v]) v = P[v] # adjust R v = T while v != S: u = P[v] R[u][v] -= min_flow # reverse path => fix prior error path R[v][u] += min_flow v = P[v] # add max flow max_flow += min_flow return max_flowS, T = 0, N-1max_flow = FF()print(max_flow)
- 图论
- 图论
- 图论
- 图论
- 图论
- 图论
- 图论
- 图论
- 图论
- 图论
- 图论
- 图论
- 图论~~!!!
- 图论
- 图论
- 图论
- 图论
- 图论
- COM技术内幕--QueryInterface函数
- 如何压制jar包
- H1838红外接收头
- 关于二进制和位运算(小结)
- playbook变量与引用
- 图论
- Sublime3快捷键
- 第十三周项目4--Floyd算法的验证
- 结构体的指针声明
- RecyclerView: No adapter attached; skipping layout
- 第14周项目1-(2)验证分块查找算法
- 第十五周 项目4:验证希尔排序
- linux透明大页介绍说明
- Android Nuwa 热修复原理和的gradle插件详解并怎么修改gradle插件