图论

来源:互联网 发布:装修 方面 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)
0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 同款商品比京东便宜怎么办 京东自营不支持7天退货怎么办 天猫买了一个月的电动车坏了怎么办 发票号码和机打号码不一致怎么办 交电费的本子弄丢了怎么办 快递正在派件中发现地址错了怎么办 快递当天送达当天签收还算延怎么办 深圳国税公众号预约取号公司怎么办 社保买了停了2年怎么办 qq号被冻结申请不回来了怎么办 qq号被冻结 手机密保忘了怎么办 微信账号封了2天怎么办 买qq号被申诉找回了怎么办 收到了京东白条的催款通知单怎么办 成都买房社保不够两年怎么办18年 电话号码给人设置成骚扰电话怎么办 找不到领导电话不接短信不回怎么办 微信账号被别人手机号冻结了怎么办 微信冻结了手机号也让人换了怎么办 顺丰快递拒收退回丢件了怎么办 京东买东西快递电话没有听到怎么办 在京东购物自己电话号输错了怎么办 北京房子卖了户口没地方迁怎么办 微信弄丢了微信密码找不到了怎么办 微信背人用过找不到密码怎么办 超市的微信支付宝收付款怎么办 办理联华超市的会员储蓄卡怎么办 卡杰文具密码本如果忘记密码怎么办 火狐浏览器阻止要访问的网页怎么办 点我达被永久停用了怎么办 刚下的软件点开系统显示停用怎么办 红酒洋酒啤酒一起喝胃不舒服怎么办 儿子13岁初一不想读书了怎么办 微信不小心点了注册新账号怎么办 在京东买东西商家不发货怎么办 在京东买东西坏了商家不退货怎么办 苯扎氯铵溶液不小心喝了一口怎么办 苯扎氯铵溶液没有稀释就用了怎么办 牛油果切开了但是没熟怎么办 手机安装程序时解析包出错怎么办 因俩人不合适分手了很难受怎么办