算法訓練營day58 圖論⑧ 拓撲排序精講、dijkstra(樸素版)精講

? ? ? ? 本篇應該是圖論的經典部分了,本篇的內容作為小白沒有了解過,但是至少會聽說過——拓撲排序精講、dijkstra(樸素版)精講。

拓撲排序精講

????????本題是拓撲排序的經典題目。一聊到 拓撲排序,一些錄友可能會想這是排序,不會想到這是圖論算法。其實拓撲排序是經典的圖論問題。

????????給出一個 有向圖,把這個有向圖轉成線性的排序 就叫拓撲排序。當然拓撲排序也要檢測這個有向圖 是否有環,即存在循環依賴的情況,因為這種情況是不能做線性排序的。所以拓撲排序也是圖論中判斷有向無環圖的常用方法

????????拓撲排序指的是一種 解決問題的大體思路, 而具體算法,可能是廣搜也可能是深搜。實現拓撲排序的算法有兩種:卡恩算法(BFS)和DFS。一般來說我們只需要掌握 BFS (廣度優先搜索)就可以了,清晰易懂,如果還想多了解一些,可以再去學一下 DFS 的思路,但 DFS 不是本篇重點。

????????當我們做拓撲排序的時候,應該優先找 入度為 0 的節點,只有入度為0,它才是出發節點。?理解以上內容很重要

????????接下來我給出 拓撲排序的過程,其實就兩步:

  1. 找到入度為0 的節點,加入結果集
  2. 將該節點從圖中移除(從頭開始循環)

????????結果集的順序,就是我們想要的拓撲排序順序 (結果集里順序可能不唯一)

判斷有環

????????那么如果我們發現結果集元素個數 不等于 圖中節點個數,我們就可以認定圖中一定有 有向環!這也是拓撲排序判斷有向環的方法。

代碼實現

? ? ? ? 并不需要一定要把節點刪除,重點在于節點入度的判斷,只要相關節點入度-1即可,重點在于對于節點入度的處理,以及通過隊列結構對于節點的遍歷,類似我們之前做到過的二叉樹的層序遍歷

# 導入必要的模塊
# deque:用于實現隊列(高效的彈出左側元素操作)
# defaultdict:用于構建鄰接表(默認值為列表,簡化鍵不存在時的處理)
from collections import deque, defaultdictdef topological_sort(n, edges):"""拓撲排序函數:對有向無環圖(DAG)進行拓撲排序,常用于解決依賴關系問題(如文件依賴、任務調度)參數:n: 節點總數(如文件數量)edges: 邊的列表,每個元素為 tuple(s, t),表示存在一條從 s 到 t 的有向邊(s 依賴 t 或 t 依賴 s,根據場景而定)功能:輸出拓撲排序結果;若圖中存在環,則輸出 -1"""# inDegree 數組:記錄每個節點的入度(即有多少個前置依賴)# 索引代表節點編號,值代表入度數量inDegree = [0] * n# umap:鄰接表,記錄節點間的依賴關系# key 是起始節點,value 是 key 指向的所有節點(列表)umap = defaultdict(list)# 構建圖(鄰接表)和入度表for s, t in edges:# s -> t 表示:要完成 t 必須先完成 s(或 t 依賴 s)# 因此 t 的入度 +1(增加一個前置依賴)inDegree[t] += 1# 在鄰接表中記錄 s 指向 t(s 完成后可處理 t)umap[s].append(t)# 初始化隊列:將所有入度為 0 的節點加入隊列# 入度為 0 表示該節點沒有前置依賴,可以直接開始處理queue = deque([i for i in range(n) if inDegree[i] == 0])# 存儲拓撲排序的結果result = []# 隊列不為空時,循環處理節點while queue:# 取出隊列左側的節點(當前可處理的節點)cur = queue.popleft()# 將當前節點加入結果列表result.append(cur)# 遍歷當前節點指向的所有節點(即依賴當前節點的節點)for file in umap[cur]:# 依賴當前節點的節點,其入度減 1(少了一個前置依賴)inDegree[file] -= 1# 若入度減為 0,說明該節點的所有前置依賴都已處理完,可加入隊列等待處理if inDegree[file] == 0:queue.append(file)# 若結果列表長度等于節點總數,說明所有節點都被處理(圖無環),輸出排序結果if len(result) == n:print(" ".join(map(str, result)))# 否則,說明圖中存在環(部分節點因入度無法減為 0 而未被處理),輸出 -1else:print(-1)if __name__ == "__main__":"""程序入口:讀取輸入并調用拓撲排序函數"""# 讀取節點總數 n 和邊數 mn, m = map(int, input().split())# 讀取 m 條邊,每條邊為 (s, t) 的元組edges = [tuple(map(int, input().split())) for _ in range(m)]# 執行拓撲排序topological_sort(n, edges)

dijkstra(樸素版)精講

????????dijkstra算法:在有權圖(權值非負數)中求從起點到其他節點的最短路徑算法。

????????需要注意兩點:

  • dijkstra 算法可以同時求 起點到所有節點的最短路徑
  • 權值不能為負數

?dijkstra三部曲

  1. 第一步,選源點到哪個節點近且該節點未被訪問過
  2. 第二步,該最近節點被標記訪問過
  3. 第三步,更新非訪問節點到源點的距離(即更新minDist數組)

????????與prim算法基本一致,區別在于?dijkstra算法是一個積累的過程對數組賦值,而prim是當下節點的值沒有累加。即:prim是求 非訪問節點到最小生成樹的最小距離,而 dijkstra是求 非訪問節點到源點的最小距離

????????prim算法 可以有負權值嗎?當然可以!prim算法只需要將節點以最小權值和鏈接在一起,不涉及到單一路徑。

對于負值

? ? ? ? 該算法不能接受權值為負數(對應算法為Bellman-Ford 算法,后續講),因為權值存在負數會對節點循環造成影響,需要多次遍歷已經訪問過的節點(之前是每個節點只會遍歷一次),會造成循環結構的困擾

import sysdef dijkstra(n, m, edges, start, end):"""Dijkstra算法實現:求解從起點到終點的最短路徑參數:n: 節點總數m: 邊的數量edges: 邊的列表,每個元素為元組(p1, p2, val),表示從p1到p2的有向邊,權重為valstart: 起點編號end: 終點編號返回:起點到終點的最短路徑長度;若無法到達,返回-1"""# 初始化鄰接矩陣,用于存儲節點間的距離# 初始值設為無窮大(float('inf')),表示初始時節點間不可達# 矩陣大小為(n+1)x(n+1),因為節點編號從1開始grid = [[float('inf')] * (n + 1) for _ in range(n + 1)]# 填充鄰接矩陣:根據邊的信息設置節點間的距離for p1, p2, val in edges:grid[p1][p2] = val  # 有向邊,僅設置p1到p2的距離# minDist數組:記錄從起點到每個節點的最短距離# 初始值設為無窮大,表示尚未確定距離minDist = [float('inf')] * (n + 1)# visited數組:標記節點是否已被訪問(即是否已確定最短路徑)visited = [False] * (n + 1)# 起點到自身的距離為0minDist[start] = 0# Dijkstra算法主循環:需要遍歷所有節點(最多n次)for _ in range(1, n + 1):# 1. 找到當前未訪問且距離起點最近的節點minVal = float('inf')  # 暫存當前最小距離cur = -1               # 暫存選中的節點# 遍歷所有節點,尋找符合條件的節點for v in range(1, n + 1):# 條件:未被訪問 且 距離起點更近if not visited[v] and minDist[v] < minVal:minVal = minDist[v]  # 更新最小距離cur = v              # 更新選中的節點# 如果找不到可訪問的節點(所有可達節點已處理),提前結束循環if cur == -1:break# 2. 標記當前節點為已訪問(其最短路徑已確定)visited[cur] = True# 3. 更新所有未訪問節點通過當前節點到達起點的距離for v in range(1, n + 1):# 條件:# - 節點v未被訪問# - 當前節點cur到v存在路徑(距離不為無窮大)# - 通過cur到達v的距離比當前已知距離更短if not visited[v] and grid[cur][v] != float('inf') and minDist[cur] + grid[cur][v] < minDist[v]:# 更新最短距離minDist[v] = minDist[cur] + grid[cur][v]# 返回結果:若終點不可達(距離仍為無窮大),返回-1;否則返回最短距離return -1 if minDist[end] == float('inf') else minDist[end]if __name__ == "__main__":"""程序入口:讀取輸入并調用Dijkstra算法計算結果"""# 一次性讀取所有輸入數據input = sys.stdin.readdata = input().split()  # 按空白字符分割成列表# 解析節點總數和邊數n, m = int(data[0]), int(data[1])# 解析所有邊的信息edges = []index = 2  # 從第三個元素開始是邊的信息for _ in range(m):p1 = int(data[index])p2 = int(data[index + 1])val = int(data[index + 2])edges.append((p1, p2, val))  # 將邊信息存入列表index += 3  # 移動到下一條邊的起始位置# 設定起點為1,終點為n(可根據實際需求修改)start = 1end = n# 調用Dijkstra算法計算最短路徑并輸出結果result = dijkstra(n, m, edges, start, end)print(result)

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

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

相關文章

如何在日常開發中高效使用 Copilot

網羅開發&#xff08;小紅書、快手、視頻號同名&#xff09;大家好&#xff0c;我是 展菲&#xff0c;目前在上市企業從事人工智能項目研發管理工作&#xff0c;平時熱衷于分享各種編程領域的軟硬技能知識以及前沿技術&#xff0c;包括iOS、前端、Harmony OS、Java、Python等方…

使用Docker部署Coze Studio開源版

1、安裝Docker# 安裝Docker https://docs.docker.com/get-docker/# 安裝Docker Compose https://docs.docker.com/compose/install/# CentOS安裝Docker https://mp.weixin.qq.com/s/nHNPbCmdQs3E5x1QBP-ueA2、安裝Coze Studio詳見&#xff1a;https://github.com/coze-dev/coze…

深度剖析Spring AI源碼(九):構建企業知識庫,深入ETL與RAG實現

深度剖析Spring AI源碼&#xff08;九&#xff09;&#xff1a;構建企業知識庫&#xff0c;深入ETL與RAG實現 “Data is the new oil, but like oil, it’s valuable only when refined.” —— 在AI時代&#xff0c;原始數據需要經過精心的ETL處理才能成為AI的"燃料"…

C# 簡單工廠模式:構建靈活與可擴展的面向對象程序

在面向對象編程&#xff08;OOP&#xff09;的世界中&#xff0c;簡單工廠模式&#xff08;Simple Factory Pattern&#xff09; 是一種非常常見且實用的設計模式。雖然它并不屬于GoF&#xff08;Gang of Four&#xff09;定義的23種經典設計模式之一&#xff0c;但它是理解更復…

全面解析JVM預熱:原理、價值與實踐指南

在Java應用的性能優化領域,“JVM預熱”是一個常被提及卻容易被忽視的關鍵環節。尤其是在高并發、低延遲的業務場景中,未經過充分預熱的JVM可能導致應用啟動初期出現響應延遲、吞吐量波動甚至服務不可用的問題。本文將從JVM預熱的核心原理出發,深入剖析其價值、常見實現方案及…

數學建模-灰色關聯分析(GRA)

目錄 1-AI帶你認識GRA &#x1f4d8; 一、灰色關聯分析&#xff08;GRA&#xff09;簡介 1. 什么是灰色關聯分析&#xff1f; 2. 核心思想&#xff08;通俗理解&#xff09;&#xff1a; 3. 與熵權法的對比&#xff08;快速類比&#xff09;&#xff1a; &#x1f9e9; 二…

Shell腳本-expect

一、前言在 Linux 系統管理與自動化運維中&#xff0c;我們經常需要編寫 Shell 腳本來完成各種任務。但有些命令&#xff08;如 ssh、scp、passwd、ftp 等&#xff09;在執行時會等待用戶手動輸入密碼或確認信息&#xff0c;這就導致腳本無法完全自動化運行。為了解決這個問題&…

Conmi的正確答案——Ubuntu24.04禁用任何休眠

系統&#xff1a;Ubuntu 24.04步驟一、禁用系統休眠服務 # 禁用所有休眠/待機相關服務&#xff08;立即生效&#xff09; sudo systemctl mask sleep.target suspend.target hibernate.target hybrid-sleep.target # 驗證狀態&#xff08;顯示 "masked" 即成功&am…

開源 C++ QT Widget 開發(二)基本控件應用

文章的目的為了記錄使用C 進行QT Widget 開發學習的經歷。臨時學習&#xff0c;完成app的開發。開發流程和要點有些記憶模糊&#xff0c;趕緊記錄&#xff0c;防止忘記。 相關鏈接&#xff1a; 開源 C QT Widget 開發&#xff08;一&#xff09;工程文件結構-CSDN博客 開源 C…

今日科技風向|從AI芯片定制到閱兵高科技展示——聚焦技術前沿洞察

今日科技風向&#xff5c;從AI芯片定制到閱兵高科技展示——聚焦技術前沿洞察 一、NVIDIA 開發“黑曜”子版 AI 芯片 B30A&#xff0c;瞄準中國市場 今日報道指出&#xff0c;NVIDIA 正在研發一款面向中國市場的定制芯片 B30A&#xff0c;基于其先進的 Blackwell 架構&#xff…

Elasticsearch官方文檔學習-未完待續

Elasticsearch官方文檔學習-未完待續說明快速開始基礎知識索引組成1. 文檔 (Documents)2. 元數據字段(Metadata fields)3. 映射和數據類型(Mappings and data types)文檔操作(Document)批量創建或者刪除文檔 (Bulk index or delete documents)樂觀并發控制 Optimistic concurre…

Redis資料

Redis是什么&#xff1f; Redis(Remote Dictionary Server)是一個開源的、基于內存的鍵值數據庫&#xff0c;支持多種數據結構&#xff0c;可用作數據庫、緩存和消息中間件。主要特點包括&#xff1a; 基于內存操作&#xff0c;讀寫性能極高支持持久化&#xff0c;可將內存數…

CAMEL-Task2-Agent的構成組件

CAMEL-Task2-Agent的構成組件 本文筆記主要關于2.7章節&#xff1a;CAMEL框架中agents如何使用工具。 一、工具說明 為什么要額外使用工具&#xff1f; agents本身的知識和能力有限&#xff0c;比如一些問題需要聯網搜索才能準確回答&#xff08;而不是亂答&#xff0c;即“…

數據整理自動化 - 讓AI成為你的數據助手

文章目錄數據整理自動化 - 讓AI成為你的數據助手引言&#xff1a;數據整理的時代挑戰與機遇1. 常見數據整理場景分析1.1 數據整理的多元場景圖譜1.2 數據質量問題的分類與影響1.3 傳統處理方法的局限性2. AI與傳統腳本的協同工作流2.1 智能數據整理架構設計2.2 協同工作流的最佳…

react速成

項目目錄package.json文件&#xff1a;包含核心兩個依賴&#xff08;react、react-dom&#xff09;和命令&#xff08;start、bulid&#xff09;src&#xff1a;源碼目錄&#xff0c;開始之用的到index.js和App.jsindex.js&#xff1a;是項目的入口&#xff0c;一切的運行起點/…

Maven的進階使用(上)

pom.xml文件 就像 Make 的 MakeFile、Ant 的 build.xml 一樣&#xff0c;Maven 項目的核心是 pom.xml。POM(全稱 Project Object Model&#xff0c;項目對象模型 ) 定義了項目的基本信息&#xff0c;用于描述項目如何構建&#xff0c;聲明項目依賴&#xff0c;等等。 Gredele--…

【最后203篇系列】034 使用SQLite構建簡單的任務管理

表數據同步的斷點續傳 有時候需要將一個表的數據復制到另一個表&#xff0c;循環是常用的方式。當表比較大&#xff0c;執行的時間很長&#xff0c;會有很多因素引起失敗。我希望可以比較簡單的跑數&#xff0c;所以做一個簡單的任務系統。 SQLitre是嵌入式數據庫&#xff0c;這…

SpringCloud Alibaba核心知識點

Spring Cloud Alibaba 是阿里巴巴開源的一套微服務解決方案&#xff0c;與 Spring Cloud 生態深度集成。以下是其主要組件及其功能&#xff1a;Nacos服務注冊與發現&#xff1a;支持動態服務注冊、健康監測及DNS-Based服務發現。配置中心&#xff1a;提供分布式配置管理&#x…

LeetCode 分類刷題:34. 在排序數組中查找元素的第一個和最后一個位置

題目給你一個按照非遞減順序排列的整數數組 nums&#xff0c;和一個目標值 target。請你找出給定目標值在數組中的開始位置和結束位置。如果數組中不存在目標值 target&#xff0c;返回 [-1, -1]。你必須設計并實現時間復雜度為 O(log n) 的算法解決此問題。示例 1&#xff1a;…

自建知識庫,向量數據庫 (十二)之 文章向量搜索——仙盟創夢IDE

“未來之窗” 文章向量搜索&#xff1a;多領域應用與學習指南 在數字化浪潮中&#xff0c;“未來之窗” 文章向量搜索憑借其獨特的技術優勢&#xff0c;在酒店、電商、診療及知識庫等多個領域展現出巨大的應用潛力&#xff0c;為各行業的信息處理與檢索帶來了全新的視角和高效…