算法訓練營day57 圖論⑦ prim算法精講、kruskal算法精講

? ? ? ? 兩種最小生成樹算法講解

prim算法精講

卡碼網53. 尋寶

????????本題題目內容為最短連接,是最小生成樹的模板題,那么我們來講一講最小生成樹。最小生成樹可以使用prim算法也可以使用kruskal算法計算出來。本篇我們先講解prim算法。

????????最小生成樹是所有節點的最小連通子圖,即:以最小的成本(邊的權值)將圖中所有節點鏈接到一起。圖中有n個節點,那么一定可以用n-1條邊將所有節點連接到一起。

????????prim算法是從節點的角度采用貪心的策略每次尋找距離最小生成樹最近的節點并加入到最小生成樹中。

????????prim算法核心就是三步,我稱為prim三部曲,大家一定要熟悉這三步,代碼相對會好些很多:

  1. 第一步,選距離生成樹最近節點
  2. 第二步,最近節點加入生成樹
  3. 第三步,更新非生成樹節點到生成樹的距離(即更新minDist數組)

????????同時,因為使用一維數組,數組的下標和數組如何賦值很重要,不要搞反,導致結果被覆蓋。

? ? ? ? 一定要理解minDist數組,簡單說就是一棵樹不斷記錄離自己最近的節點,并吸收進來,再不斷循環這個過程

????????不斷吸收新節點,不斷以樹外節點離樹最近的距離做更新,并更新樹,循環,最后達到下圖效果,具體過程為綠色部分不斷延伸(即minDist數組不斷更新),最終計算數組和即可

代碼實現

????????記錄邊,注意初始化數組大小

def prim(v, e, edges):"""Prim算法實現,用于求解無向連通圖的最小生成樹(MST)總權重參數:v: 頂點數量e: 邊的數量edges: 邊的列表,每個元素為元組(x, y, k),表示頂點x與y之間的邊權重為k返回:最小生成樹的總權重"""import sysimport heapq  # 雖然導入了heapq但未使用,可能是預留或之前版本的殘留# 初始化鄰接矩陣,大小為(v+1)x(v+1)(頂點編號從1開始)# 初始值設為10001表示無窮大(假設所有邊的權重都小于此值)grid = [[10001] * (v + 1) for _ in range(v + 1)]# 讀取邊的信息并填充鄰接矩陣# 由于是無向圖,x到y和y到x的權重相同for edge in edges:x, y, k = edge  # x和y為兩個頂點,k為邊的權重grid[x][y] = kgrid[y][x] = k# minDist數組:記錄每個非樹節點到生成樹的最短距離# 索引0未使用(頂點編號從1開始)minDist = [10001] * (v + 1)# 從頂點1開始構建生成樹,因此將其到生成樹的距離設為0minDist[1] = 0# isInTree數組:標記頂點是否已加入生成樹# True表示已加入,False表示未加入isInTree = [False] * (v + 1)# Prim算法主循環:需要加入v-1條邊(構建包含所有v個頂點的樹)for i in range(1, v):# 1. 找到當前未加入生成樹且距離最近的頂點cur = -1  # 存儲當前選中的頂點minVal = sys.maxsize  # 存儲當前最小距離(初始為系統最大整數)# 遍歷所有頂點,尋找符合條件的頂點for j in range(1, v + 1):# 條件:未加入生成樹 且 距離生成樹更近if not isInTree[j] and minDist[j] < minVal:minVal = minDist[j]  # 更新最小距離cur = j  # 更新選中的頂點# 2. 將找到的最近頂點加入生成樹isInTree[cur] = True# 3. 更新所有未加入生成樹的頂點到生成樹的最短距離# 以剛加入的cur頂點為中間點,檢查是否有更短路徑for j in range(1, v + 1):# 條件:未加入生成樹 且 通過cur頂點能獲得更短距離if not isInTree[j] and grid[cur][j] < minDist[j]:minDist[j] = grid[cur][j]  # 更新最短距離# parent[j] = cur; // 記錄最小生成樹的邊 (注意數組指向的順序很重要)# 計算最小生成樹的總權重:累加頂點2到v的最小距離(頂點1為起點,距離0)result = sum(minDist[2:v+1])return resultif __name__ == "__main__":"""程序入口:讀取輸入數據并調用prim函數計算結果"""import sys# 讀取所有輸入數據(一次性讀取提高效率,適用于大數據量)input = sys.stdin.readdata = input().split()  # 將輸入按空白字符分割為列表# 解析頂點數和邊數(前兩個元素)v = int(data[0])e = int(data[1])# 解析所有邊的信息edges = []index = 2  # 從第三個元素開始是邊的信息for _ in range(e):x = int(data[index])y = int(data[index + 1])k = int(data[index + 2])edges.append((x, y, k))  # 將邊信息存入列表index += 3  # 移動到下一條邊的起始位置# 調用prim算法計算結果并輸出result = prim(v, e, edges)print(result)

kruskal算法精講

? ? ? ? 通過貪心的思路,從邊出發,(在是否同一集合的情況下判斷)不斷吸收最小權值的邊。再次注意本題是要求連接所有節點!!

????????但在代碼中,如果將兩個節點加入同一個集合,又如何判斷兩個節點是否在同一個集合呢?我們在并查集開篇的時候就講了,并查集主要就兩個功能:

  • 將兩個元素添加到一個集合中
  • 判斷兩個元素在不在同一個集合

代碼實現

? ? ? ? 本題圖示是綠色線條的不斷延伸(每次多一條邊),上題為以節點為中心不斷更新最短距離數組

????????lambda?是 Python 中的匿名函數,語法為?lambda 參數: 表達式,通常用于簡化代碼,lambda?中的?edge?是一個形參sort?方法在遍歷?edges?時會自動將列表中的每個元素作為實參傳給它,因此?edge?能依次指向?edges?中的所有元素

# 定義邊(Edge)類,用于存儲一條邊的信息
class Edge:def __init__(self, l, r, val):self.l = l      # 邊的左頂點self.r = r      # 邊的右頂點self.val = val  # 邊的權重值# 初始化常量和并查集數組
n = 10001               # 最大頂點數限制
father = list(range(n)) # 并查集數組,father[u]表示u的父節點def init():"""初始化并查集,讓每個節點的父節點都是自己"""global fatherfather = list(range(n))def find(u):"""查找節點u的根節點,同時進行路徑壓縮路徑壓縮是為了加快后續的查詢速度"""if u != father[u]:# 遞歸查找根節點,并將當前節點的父節點直接指向根節點father[u] = find(father[u])return father[u]def join(u, v):"""合并兩個集合:將節點v所在的集合合并到節點u所在的集合前提是u和v已經是各自集合的根節點"""u = find(u)v = find(v)if u != v:# 將v的父節點設置為u,實現兩個集合的合并father[v] = udef kruskal(v, edges):"""Kruskal算法實現:求解最小生成樹的總權重參數:v: 頂點數量edges: 邊的列表,每個元素是Edge對象返回:最小生成樹的總權重"""# 1. 按邊的權重從小到大排序(核心步驟)edges.sort(key=lambda edge: edge.val)# 2. 初始化并查集init()# 3. 存儲最小生成樹的總權重result_val = 0# 4. 遍歷所有排序后的邊,嘗試加入生成樹for edge in edges:# 查找兩個頂點所在集合的根節點x = find(edge.l)y = find(edge.r)# 如果根節點不同,說明不在同一個集合,不會形成環if x != y:# 將這條邊加入最小生成樹result_val += edge.val# 合并兩個集合join(x, y)return result_valif __name__ == "__main__":"""程序入口:讀取輸入并調用Kruskal算法計算結果"""import sys# 一次性讀取所有輸入數據input = sys.stdin.readdata = input().split()  # 按空白字符分割成列表# 解析頂點數和邊數v = int(data[0])e = int(data[1])# 解析所有邊的信息edges = []index = 2  # 從第三個元素開始是邊的信息for _ in range(e):v1 = int(data[index])v2 = int(data[index + 1])val = int(data[index + 2])edges.append(Edge(v1, v2, val))  # 創建Edge對象并添加到列表index += 3  # 移動到下一條邊的起始位置# 調用Kruskal算法計算結果并輸出result_val = kruskal(v, edges)print(result_val)

拓展

????????在節點數量固定的情況下,圖中的邊越少,Kruskal 需要遍歷的邊也就越少。而 prim 算法是對節點進行操作的,節點數量越少,prim算法效率就越優。所以在 稀疏圖中,用Kruskal更優。 在稠密圖中,用prim算法更優。

????????為什么邊少的話,使用 Kruskal 更優呢因為 Kruskal 是對邊進行排序的后 進行操作是否加入到最小生成樹。邊如果少,那么遍歷操作的次數就少。

????????Prim 算法 時間復雜度為 O(n^2),其中 n 為節點數量,它的運行效率和圖中邊樹無關,適用稠密圖。

????????Kruskal算法 時間復雜度 為 nlogn,其中n 為邊的數量,適用稀疏圖

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/93909.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/93909.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/93909.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

148-基于Python的2024物流年度銷售收入數據可視化分析系統

基于Python Django的物流數據可視化分析系統開發實錄 項目背景 隨著物流行業數據量的激增&#xff0c;企業對數據分析和可視化的需求日益增長。傳統的Excel分析方式難以滿足多維度、實時、交互式的數據洞察需求。為此&#xff0c;我們開發了一個基于Python Django的物流年度銷售…

Python中的關鍵字參數:靈活與可讀性的完美結合(Effective Python 第23條)

在Python編程中&#xff0c;函數參數的傳遞方式靈活多樣&#xff0c;而其中一種特別強大的方式就是關鍵字參數。關鍵字參數不僅能夠提升代碼的可讀性&#xff0c;還為函數的設計和調用提供了極大的便利。本文將深入探討關鍵字參數的用法、優勢以及實際應用中的注意事項。 一、關…

005.Redis 主從復制架構

主從復制概念與原理 核心概念 主節點&#xff08;Master&#xff09;&#xff1a;唯一接受寫操作的節點&#xff0c;數據修改后異步復制到從節點。 從節點&#xff08;Replica&#xff09;&#xff1a;復制主節點數據的節點&#xff0c;默認只讀&#xff08;可配置為可寫但不…

Android Studio 模擬器 “******“ has terminated 問題

問題&#xff1a;Android Studio 模擬器 "**" has terminated 問題設備信息&#xff1a;CPU:I5 7500U RAM:64GB System:Windows 10 64位解決&#xff1a; 網上所有辦法都嘗試后仍然不可行可嘗試如下辦法&#xff1a;1、此電腦→管理→設備管理→顯示適配器→右擊→…

uniapp 懶加載圖片

實現的功能 1.一次性獲取圖片。 2.按用戶視野范圍內看到的圖片滾動下來進行懶加載,提高瀏覽器性能。 3.不要一次性加載全部的圖片 1.給父組件綁定一個滾動監聽 1.頁面路徑:/pages/Home/index.vue 不在一個頁面的話用 EventBus去觸發。@scroll="handleScroll2" Ev…

Android - 資源類型 MINE Type

一、概念MINE&#xff08;Multipurpose Internet Mail Extensions&#xff09;最初是為了標識電子郵件附件的類型&#xff0c;在 HTML 中使用 content-type 屬性表示&#xff0c;描述了文件類型的互聯網標準。格式&#xff1a;媒體類型/子類型&#xff0c;可使用通配符*。如 au…

php8.+ 新函數總結

PHP系統函數是PHP核心提供的內置函數&#xff0c;用于執行常見任務&#xff0c;如字符串操作、數組處理、數學運算等。它們通過預定義代碼塊封裝了特定功能&#xff0c;開發者可直接調用而無需重復編寫代碼。 而 PHP 8.0以后又新增了一些實用函數&#xff0c;今天總結部分常見的…

Qt事件處理機制詳解

一、事件處理基本流程在Qt中&#xff0c;所有從QObject派生的類都能處理事件。事件處理的核心流程如下&#xff1a;事件入口函數&#xff1a;bool QObject::event(QEvent *e)參數e包含事件信息&#xff0c;通過e->type()獲取事件類型返回值true表示事件已被處理&#xff0c;…

Zynq中級開發七項必修課-第三課:S_AXI_GP0 主動訪問 PS 地址空間

Zynq中級開發七項必修課-第三課&#xff1a;S_AXI_GP0 主動訪問 PS 地址空間 目標1.0 編寫 AXI-Lite Master&#xff1a;按鍵計數 → 寫入 PS 內存1.1 PL 觸發中斷 → PS 響應并串口打印按鍵計數值BD圖axi_lite_master.v // // AXI4-Lite Simple Master (single-shot, non-pip…

CVPR | 2025 | MAP:通過掩碼自回歸預訓練釋放混合 Mamba - Transformer 視覺骨干網絡的潛力

文章目錄CVPR | 2025 | MAP&#xff1a;通過掩碼自回歸預訓練釋放混合 Mamba - Transformer 視覺骨干網絡的潛力創新點初步研究初步結論方法確定一個混合網絡方法掩碼機制掩碼比例MAP的transformer解碼器重建目標實驗ImageNet-1k 上的 2D 分類CVPR | 2025 | MAP&#xff1a;通過…

Spring Boot + Spring AI 最小可運行 Demo

一. 項目依賴&#xff08;pom.xml&#xff09;<project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/POM/4.0.0https://maven.apache.org/xsd/mav…

AI重塑校園教育:中小學AI智慧課堂定制方案+AI作業批改減負,告別一刀切學生進步快

家長們&#xff0c;你有沒有聽過孩子抱怨上學的煩惱&#xff1f;課堂上老師講的內容&#xff0c;有的同學覺得太簡單 “吃不飽”&#xff0c;有的卻跟不上 “聽不懂”&#xff1b;放學后作業堆成山&#xff0c;老師要熬夜批改到半夜&#xff0c;錯題反饋要等第二天才能拿到&…

舊物循環,交易新生——舊物回收二手交易小程序,引領綠色消費新風尚

在資源日益緊張、環境污染問題日益突出的今天&#xff0c;綠色消費已經成為時代發展的必然趨勢。舊物回收二手交易小程序&#xff0c;作為綠色消費的重要載體&#xff0c;正以其獨特的優勢和魅力&#xff0c;引領著一場關于舊物循環、交易新生的綠色革命。一、舊物循環&#xf…

刷機維修進階教程-----如何清除云賬號 修復wifi 指南針 相機 指紋等刷機故障

在刷機、系統升級或降級過程中,是否遇到過以下問題:WiFi無法開啟、相機無響應、指南針或陀螺儀失靈 指紋等故障?另外,云賬號是否仍會保留,即使通過9008模式刷機也無法徹底清除?那么這篇博文都可以找到答案。 通過博文了解?????? 1??????----云賬號信息分區如…

AI翻唱實戰:用[靈龍AI API]玩轉AI翻唱 – 第6篇

歷史文章 [靈龍AI API] 申請訪問令牌 - 第1篇 [靈龍AI API] AI生成視頻API&#xff1a;文生視頻 – 第2篇 圖生視頻實戰&#xff1a;用[靈龍AI API]玩轉AI生成視頻 – 第2篇&#xff0c;從靜圖到大片 單圖特效實戰&#xff1a;用[靈龍AI API]玩轉AI生成視頻 – 第3篇&#…

大模型0基礎開發入門與實踐:第11章 進階:LangChain與外部工具調用

第11章 進階&#xff1a;LangChain與外部工具調用 1. 引言 在上一章&#xff0c;我們成功地創造了我們的第一個“生命”——一個可以對話的機器人。我們為它的誕生而興奮&#xff0c;但很快我們就會發現它的局限性。它就像一個被囚禁在玻璃房中的天才大腦&#xff0c;擁有淵博…

SQL 日期處理:深入解析與高效實踐

SQL 日期處理&#xff1a;深入解析與高效實踐 引言 在數據庫管理中&#xff0c;日期和時間數據的處理是不可或缺的一部分。SQL&#xff08;結構化查詢語言&#xff09;提供了豐富的日期和時間函數&#xff0c;使得對日期的處理變得既靈活又高效。本文將深入探討SQL日期處理的相…

源代碼部署 LAMP 架構

源代碼部署 LAMP 架構 &#xff08;Linux Apache MySQL PHP&#xff09; 一、LAMP 架構概述 LAMP 是一套經典的開源 Web 服務架構&#xff0c;通過源代碼安裝可實現高度定制化&#xff0c;適用于對軟件版本、功能模塊有特定需求的場景。本指南基于 CentOS 7 系統&#xf…

GO環境變量中GO111MODULE到底是干啥的?

查看GO111MODULE變量GO111MODULE的作用GO111MODULE的案例演示 一&#xff0c;查看GO111MODULE變量 ]# go env GO111MODULE 或者 ]# go env | grep GO111MODULE二&#xff0c;GO111MODULE的作用 auto : 自動判斷機制 當項目位于 $GOPATH/src 目錄外且包含 go.mod 文件時&…

在線培訓機構如何降低培訓視頻被盜錄的風險

每一節精心錄制的培訓視頻&#xff0c;都凝聚著講師的心血與機構的巨大投入。然而&#xff0c;只需一個簡單的錄屏軟件&#xff0c;這一切都可能被輕易竊取。一旦被盜取&#xff0c;不但會損失經濟利益&#xff0c;還可能會影響機構的聲譽。那么&#xff0c;在線培訓機構如何降…