1. 程式人生 > >圖論題目模板,和並查集:以後的圖論題目就靠他了

圖論題目模板,和並查集:以後的圖論題目就靠他了

fat union 一次 情況 返回 end empty 是我 min

技術分享圖片
‘‘‘
並查集:
1.用於查如何A,B是否在一個集合中.
2.每一個集合設立一個頭結點.其他都連向他
3.集合合並就是把小的集合掛到大的集合下面即可
4.優化.查詢到一個a在b這個頭結點下面,那麽直接把a.next=b
‘‘‘
class bingcha():
    def __init__(self):

        self.fathermap={}
        self.sizemap={}
    def make_sets(self,list1):#把數據集list賦值到並查集裏面做初始化
        for i in range(len(list1)):
            self.fathermap[list1[i]]
=list1[i] self.sizemap[list1[i]]=1 def find_father(self,node):#返回node的父節點是誰,然後把node掛到父節點上. father=node if self.fathermap[node]!=node: father=self.find_father(self.fathermap[node]) self.fathermap[node]=father return father def union(self,node1,node2): father1
=self.find_father(node1) father2=self.find_father(node2) if father1!=father2: size1=self.sizemap[father1] size2=self.sizemap[father2] if size1>=size2: self.fathermap[node2]=father1 self.sizemap[father1]+=size2
else: self.fathermap[node1]=father2 self.sizemap[father2]+=size1 def in_same_set(self,node1,node2): return self.find_father(node1)==self.find_father(node2) a=bingcha() a.make_sets([1,2,3,4,5]) a.union(1,2) a.union(1,3) a.union(1,4) print(a.in_same_set(2,4)) print(a.find_father(4)) #解決了並查集的代碼實現.從直觀上也能看出來,當已經查詢或者插入了N次 #再進行查詢操作的畫效率O(1).因為都已經連到根了.搜索1次即可. #繼續理解並查集:他用樹的加速來實現了並和查的操作,雖然他效率非常快, #但是不能進行交的操作.這就是他跟set的區別.set復雜度O(N). #並查集在圖裏面很實用.雖然面試對圖考的不多,但是應該掌握. #下面就是左神給的圖論問題模板,非常強大.能實現所有圖論問題 #使用方法:對有向圖就用graphgenerate,插入所有邊即可.順道就所有點都有了 # 對無向圖,就插入2次,一次是from to 一次是to from即可. ‘‘‘ 開始搞圖:設計好幾個類,然後存圖,左神給的是鄰接數組. ‘‘‘ class node(): def __init__(self,val): self.val=val self.in1=0 self.out=0 self.nexts=[] self.edges=[] class edge(): def __init__(self,weight,from1,to): self.weight=weight self.from1=from1 self.to=to #需要手動寫上這幾個比較函數. def __cmp__(self,other): return cmp(self.weight, other.weight) def __lt__(self,other):#operator < return self.weight < other.weight def __ge__(self,other):#oprator >= return self.weight >= other.weight def __gt__(self,other):#oprator >= return self.weight > other.weight def __le__(self,other):#oprator <= return self.weight <= other.weight class Graph(): def __init__(self): self.nodes={} #結構是key是題目給的編號,value是自己構造的node節點對象. #node.value也是編號. #因為要做復雜處理,所以第一步都是把對應編號轉化成為node對象來進行處理. self.edges=set() def GraphGenerator(matrix):#給矩陣,每一行都是 from,end,邊長, 3個元素組成. graph=Graph() for i in range(len(matrix)): from1=matrix[i][0] to=matrix[i][1] weight=matrix[i][2] graph.nodes.setdefault(from1,node(from1)) graph.nodes.setdefault(to,node(to)) fromNode=graph.nodes[from1] toNode=graph.nodes[to] newEdge=edge(weight,fromNode,toNode)#這裏面用node來做edge參數好麽? fromNode.nexts.append(toNode) fromNode.out+=1 toNode.in1+=1 fromNode.edges.append(newEdge) graph.edges.add(newEdge) return graph ‘‘‘ 寬度優先遍歷也叫廣度優先遍歷. ‘‘‘ ‘‘‘ 先寫寬度便利:#利用一個隊列和一個set ‘‘‘ import queue def bfs(node): q=queue.Queue() q.put(node) visited=set([node]) while q.empty()==False: tmp=q.get() print(tmp.val)#遍歷的操作 for i in tmp.nexts: if i not in visited: visited.add(i) q.put(i) graph=GraphGenerator([[1,2,3],[2,4,5],[2,6,7],[4,6,5],[1,6,99],[99,98,999]]) print(ceshi) (bfs(graph.nodes[1])) #graph.nodes[1]表示1號節點對應的node ‘‘‘ 深度優先:只用一個set就行 ‘‘‘ ##我自己寫的菜鳥版本.函數每次都帶visited.太慢了.左神用的是棧,來直接模擬遞歸過程. #def dfs(node): #為了設立局部所以用函數嵌套來寫,因為第一次運行時候,跟後面的代碼要不同, # #多一行初始化visited,然後後面為了保持每個visited在每一次函數時候都一樣,就傳進去. # visited=set([node]) # def mini_dfs(node,visited): # print(node.val)#遍歷的操作 # for i in node.nexts: # if i not in visited: # mini_dfs(i,visited) # visited.add(i) # mini_dfs(node,visited) # return #dfs(graph.nodes[1]) def dfs(node):#大神的版本 visited=set() fuzhu=[node] while fuzhu!=[]: node=fuzhu.pop() if node not in visited: print(node.val) visited.add(node) #node打印過了,就趕緊把他放visited裏面.避免重復訪問. for i in node.nexts: if i not in visited:#如果還有node的兒子i是沒有訪問過的,那麽需要把node,i壓回去. #就是用這個棧來替代遞歸過程.也就是遞歸改遞推. fuzhu.append(node) fuzhu.append(i) break print(ceshi2) dfs(graph.nodes[1]) ‘‘‘ 拓撲排序: 找到全部入度為0的,全做完,然後刪除這些節點相關的點和邊,繼續循環即可. ‘‘‘ def tuopu(graph):#任何一個有向無環圖才可以拓撲排序 a=queue.Queue() for i in graph.nodes.values(): if i.in1==0:#入度是0.in是關鍵字沒發使用,所以改成in1 a.put(i) result=[] while a.empty()==False: tmp=a.get() result.append(tmp) for i in tmp.nexts: i.in1-=1 if i.in1==0: a.put(i) return result print(測試3) for i in tuopu(graph): print(i.val) ‘‘‘ 最小生成樹p算法. ‘‘‘ ‘‘‘ 最小生成樹k算法. 這尼瑪:直接貪心,每一次都選權重最小的邊.不產生回路就加進來. 最後所有點都有了,就結束.你媽這麽簡單??????居然不會產生bug.頓時感覺最小生成樹很low 左神的最牛逼代碼,用並查集來判斷回路.有公共祖先就是有回路. ‘‘‘ from queue import PriorityQueue as PQueue import heapq def krustalMST(graph):#k算法實在是太短了.同樣下面K算法也可以處理不連通的情況 output=set() a=bingcha() a1=list(graph.nodes.values()) a.make_sets(a1)#把所有nodes放並查集裏面 pq = PQueue()#給edge類加一個cmp方法即可. for i in graph.edges: pq.put(i) while pq.empty()!=True: tmp=pq.get() #如果tmp的from 和to 是在並查集裏面有公共祖先的就不要了 if a.in_same_set(tmp.from1,tmp.to)!=True:#表示不是環路 #那麽就加入這個變 output.add(tmp) a.union(tmp.from1,tmp.to) return output#返回的是邊的set print(ceshi4) for i in krustalMST(graph): print(i.weight,i.from1.val,i.to.val)#效果可以.雖然是針對無向圖,但是沒有插入反向from1,to也效果 #一樣,因為我們考察的是邊. ‘‘‘ 最小生成樹:P算法.隨便加進去一個點,然後找這個點的edge,加到pq裏面,pq彈出一個最小的,加入tonode.循環 即可. ‘‘‘ def PrimMST(graph): output=set() result=set() pq=PQueue() for i in graph.nodes.values():#這個循環來處理整個圖不聯通的情況. if i not in output: output.add(i) for edge in i.edges: pq.put(edge) while pq.empty()!=True: tmp=pq.get()#道理都是每一次盡量走最短的邊, if tmp.to not in output: result.add(tmp)#當彈出的邊正好to節點沒有訪問,就是我們要的,放入result中! output.add(tmp.to) for pp in tmp.to.edges: pq.put(pp) #當新插入節點後,邊的隊列pq也更新一下即可. return result print(ceshi5) for i in PrimMST(graph): print(i.weight,i.from1.val,i.to.val)
View Code

圖論題目模板,和並查集:以後的圖論題目就靠他了