算法訓練營DAY57 第十一章:圖論part07

prim算法精講

53. 尋寶(第七期模擬筆試)

題目描述:

在世界的某個區域,有一些分散的神秘島嶼,每個島嶼上都有一種珍稀的資源或者寶藏。國王打算在這些島嶼上建公路,方便運輸。

不同島嶼之間,路途距離不同,國王希望你可以規劃建公路的方案,如何可以以最短的總公路距離將所有島嶼聯通起來。

給定一張地圖,其中包括了所有的島嶼,以及它們之間的距離。以最小化公路建設長度,確保可以鏈接到所有島嶼。

輸入描述:

第一行包含兩個整數V和E,V代表頂點數,E代表邊數。頂點編號是從1到V。例如:V=2,一個有兩個頂點,分別是1和2。

接下來共有E行,每行三個整數v1,v2和val,v1和v2為邊的起點和終點,val代表邊的權值。

輸出描述:

輸出聯通所有島嶼的最小路徑總距離

輸入示例:

7 11
1 2 1
1 3 1
1 5 2
2 6 1
2 4 2
2 3 2
3 4 1
4 5 1
5 6 2
5 7 1
6 7 1

輸出示例:

6

解題思路

本題是最小生成樹的模板題,最小生成樹可以使用prim算法也可以使用kruskal算法計算出來。

最小生成樹是所有節點的最小連通子圖,即:以最小的成本(邊的權值)將圖中所有節點鏈接到一起。

圖中有n個節點,那么一定可以用n-1條邊將所有節點連接到一起。

那么如何選擇這n-1條邊就是最小生成樹算法的任務所在。

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

prim三部曲

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

“每次尋找距離最小生成樹最近的節點并加入到最小生成樹中”,就用到了minDist數組,minDist數組用來記錄每一個節點距離最小生成樹的最近距離

初始狀態

minDist數組里的數值初始化為最大數,現在還沒有最小生成樹,默認每個節點距離最小生成樹是最大的,這樣后面我們在比較的時候,發現更近的距離,才能更新到minDist數組上。

第一步:選距離生成樹最近節點

選擇距離最小生成樹最近的節點,加入到最小生成樹,剛開始還沒有最小生成樹,所以隨便選一個節點加入就好

第二步:最近節點加入生成樹

此時節點1已經算最小生成樹的節點。

第三步:更新非生成樹節點到生成樹的距離(即更新minDist數組)
#include<iostream>
#include<vector>
#include<climits>using namespace std;
int main(){int v,e;cin>>v>>e;int x,y,k;vector<vector<int>> grid(v+1,vector<int>(v+1,10001));while(e--){cin>>x>>y>>k;grid[x][y]=k;grid[y][x]=k;}// 所有節點到最小生成樹的最小距離vector<int> minDist(v+1,10001);// 這個節點是否在樹里vector<bool> isInTree(v+1,false);
// 我們只需要循環 n-1次,建立 n - 1條邊,就可以把n個節點的圖連在一起for(int i=1;i<v;i++){//1、第一步:選距離生成樹最近節點int cur=-1;// 選中哪個節點 加入最小生成樹int minVal=INT_MAX;for(int j=1;j<=v;j++){// 1 - v,頂點編號,這里下標從1開始//  選取最小生成樹節點的條件://  (1)不在最小生成樹里//  (2)距離最小生成樹最近的節點if(!isInTree[j]&&minDist[j]<minVal){minVal=minDist[j];cur=j;}}//2、第二步:最近節點(cur)加入生成樹isInTree[cur]=true;//3、第三步:更新非生成樹節點到生成樹的距離(即更新minDist數組)// cur節點加入之后, 最小生成樹加入了新的節點,那么所有節點到 最小生成樹的距離(即minDist數組)需要更新一下// 由于cur節點是新加入到最小生成樹,那么只需要關心與 cur 相連的 非生成樹節點 的距離 是否比 原來 非生成樹節點到生成樹節點的距離更小了呢for(int j=1;j<=v;j++){// 更新的條件:// (1)節點是 非生成樹里的節點// (2)與cur相連的某節點的權值 比 該某節點距離最小生成樹的距離小// 很多錄友看到自己 就想不明白什么意思,其實就是 cur 是新加入 最小生成樹的節點,那么 所有非生成樹的節點距離生成樹節點的最近距離 由于 cur的新加入,需要更新一下數據了if(!isInTree[j]&&grid[cur][j]<minDist[j]){minDist[j]=grid[cur][j];}}}int res=0;for(int i=2;i<=v;i++){res+=minDist[i];}cout<<res<<endl;
}

拓展

上面講解的是記錄了最小生成樹所有邊的權值,如果讓打印出來最小生成樹的每條邊呢?或者說要把這個最小生成樹畫出來呢?

此時有兩個問題:

  • 1、用什么結構來記錄
  • 2、如何記錄

如果記錄邊,其實就是記錄兩個節點就可以,兩個節點連成一條邊。

如何記錄兩個節點呢?

我們使用一維數組就可以記錄。parent[節點編號] = 節點編號,這樣就把一條邊記錄下來了。(當然如果節點編號非常大,可以考慮使用map)

minDist數組里記錄的其實也是最小生成樹的邊的權值。”

既然minDist數組記錄了最小生成樹的邊,是不是就是在更新minDist數組的時候,去更新parent數組來記錄一下對應的邊呢。

所以在prim三部曲中的第三步,更新parent數組,代碼如下:

for (int j = 1; j <= v; j++) {if (!isInTree[j] && grid[cur][j] < minDist[j]) {minDist[j] = grid[cur][j];parent[j] = cur; // 記錄最小生成樹的邊 (注意數組指向的順序很重要)}
}

如果?parent[cur] = j?這么寫,最后更新的邏輯是 parent[1] = 2, parent[1] = 3, parent[1] = 4,最后只能記錄節點1與節點4相連,其他相連情況都被覆蓋了。

如果這么寫?parent[j] = cur,那就是 parent[2] = 1, parent[3] = 1, parent[4] = 1 ,這樣才能完整表示出節點1與其他節點都是鏈接的,才沒有被覆蓋。

kruskal算法精講

53. 尋寶(第七期模擬筆試)

解題思路

prim 算法是維護節點的集合,而 Kruskal 是維護邊的集合

kruscal的思路:

  • 邊的權值排序,因為要優先選最小的邊加入到生成樹里
  • 遍歷排序后的邊
    • 如果邊首尾的兩個節點在同一個集合,說明如果連上這條邊圖中會出現環
    • 如果邊首尾的兩個節點不在同一個集合,加入到最小生成樹,并把兩個節點加入同一個集合

而判斷兩個節點是否在同一個集合中,就用到了前面講的并查集;

#include<iostream>
#include<vector>
#include<algorithm>using namespace std;struct Edge{int l,r,val;
};
int n=10001;
vector<int> father(n,-1);void init(){for(int i=0;i<n;i++){father[i]=i;}
}
int find(int u){if(father[u]==u)return u;father[u]=find(father[u]);return father[u];
}
void join(int u,int v){u=find(u);v=find(v);if(u==v)return;father[v]=u;
}int main(){int v,e;cin>>v>>e;int x,y,k;vector<Edge> edges; int res=0;vector<vector<int>> grid(v+1,vector<int>(v+1,10001));while(e--){cin>>x>>y>>k;edges.push_back({x,y,k});}sort(edges.begin(),edges.end(),[](const Edge& a,const Edge& b){return a.val<b.val;});init();for(Edge edge:edges){int i=find(edge.l);int j=find(edge.r);if(i!=j){res+=edge.val;join(i,j);}}cout<<res<<endl;return 0;
}

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

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

相關文章

最短路問題從入門到負權最短路

一&#xff0c;BFS層次最短路/*題目描述 題目描述 給出一個 N 個頂點 M 條邊的無向無權圖&#xff0c;頂點編號為 1~N。 問從頂點 1 開始&#xff0c;到其他每個點的最短路有幾條。 輸入格式 第一行包含 2 個正整數 N,M&#xff0c;為圖的頂點數與邊數。 接下來 M 行&#xff…

AI智能體小白入門指南

AI智能體小白入門指南 ——什么是AI智能體&#xff1f;它們如何工作&#xff1f; 一、AI智能體是什么&#xff1f; AI智能體&#xff08;AI Agent&#xff09;是能感知環境、自主決策并執行動作的人工智能系統。 類比理解&#xff1a;像一個“虛擬機器人”或“數字助手”&#…

《設計模式》策略模式

1.策略模式定義 策略模式&#xff08;Strategy Pattern&#xff09;是一種行為型設計模式&#xff0c;它定義了一組算法&#xff0c;將每個算法封裝起來&#xff0c;并使它們可以相互替換&#xff0c;從而讓算法的變化獨立于使用它的客戶&#xff08;Client&#xff09;。 換…

AWS DMS 深度解析:從遷移任務到復制任務 - 全流程指南與最佳實踐

AWS Database Migration Service (DMS) 是一項強大的云服務,用于在源數據庫和目標數據庫之間安全地遷移數據。其核心優勢在于支持幾乎零停機時間的遷移,這主要歸功于其“變更數據捕獲 (CDC)”功能。理解遷移任務 (Migration Task) 和復制任務 (Replication Task) 的關系與操作…

國企社招 | 中國郵政2025年社會招聘開啟

添加圖片注釋&#xff0c;不超過 140 字&#xff08;可選&#xff09; 添加圖片注釋&#xff0c;不超過 140 字&#xff08;可選&#xff09; 添加圖片注釋&#xff0c;不超過 140 字&#xff08;可選&#xff09; 原文鏈接&#xff1a;“郵”你“政”好 | 廣東郵政2025年社會…

linux添加自啟動

linux添加自啟動 配置步驟&#xff1a; 創建systemd服務文件 sudo nano /etc/systemd/system/tme-vod.service將下面artifact中的內容復制到該文件中。 [Unit] DescriptionTME VOD Service Afternetwork.target[Service] Typesimple Userroot Grouproot WorkingDirectory/data/…

輕量級解決方案:如何高效處理Word轉PDF?

文檔格式轉換時&#xff0c;手動逐個處理總顯得效率低下。它的體積小巧&#xff0c;不到1MB&#xff0c;且無界面設計&#xff0c;運行極簡&#xff1a;將其與Word文件放入同一目錄&#xff0c;雙擊啟動&#xff0c;程序便會自動完成所有文檔的PDF轉換。操作零復雜度&#xff0…

Redis 數據傾斜

Redis 數據傾斜指的是在 Redis 集群模式下&#xff0c;數據&#xff08;以及相應的訪問請求和負載&#xff09;在各個分片&#xff08;Shard&#xff09;之間分布嚴重不均勻的現象。這會導致部分節點成為熱點或超載&#xff0c;而其他節點資源閑置&#xff0c;最終引發性能瓶頸…

Java基礎-TCP通信(多發多收和一發一收)

目錄 案例要求&#xff1a; 實現思路&#xff1a; 代碼&#xff1a; User:客戶端 Client:服務端 總結&#xff1a; 案例要求&#xff1a; 實現TCP通信的多發多收和一發一收,多發多收去掉各自的while循環就是一發一收,本文只模擬一發一收 實現思路&#xff1a; 客戶端(U…

WinForm 對話框的 Show 與 ShowDialog:阻塞與非阻塞的抉擇

目錄 核心概念&#xff1a;阻塞與非阻塞 Show 與 ShowDialog 的詳細對比 代碼示例&#xff1a;兩種方式的實現差異 使用 Show () 顯示非模態對話框 使用 ShowDialog () 顯示模態對話框 適用場景分析 適合使用 Show () 的場景 適合使用 ShowDialog () 的場景 最佳實踐與…

曉知識: 動態代理與靜態代理的區別

動態代理與靜態代理的區別 代理模式是一種常見的設計模式&#xff0c;用于在不修改原始類的情況下擴展其功能。代理分為靜態代理和動態代理兩種&#xff0c;它們在實現方式、適用場景和靈活性上有顯著差異。 靜態代理 靜態代理在編譯時就已經確定代理類和被代理類的關系。代理類…

Linux系統編程Day9 -- gdb (linux)和lldb(macOS)調試工具

往期內容回顧 Git 教程&#xff08;初階&#xff09; 基于Linux系統知識的第一個程序 自動化構建工具-make/Makefile gcc/g編譯及鏈接 Vim工具的使用 Linux常用工具&#xff08;yum與vim&#xff09; 一、 Linux 下的調試工具 GDB 一、為什么要學習 GDB&#xff1f; 調試是開發…

數據結構(17)排序(下)

一、計數排序計數排序又稱為鴿巢原理&#xff0c;是對哈希直接定址法的變形應用。操作步驟如下&#xff1a;①統計相同元素出現的次數 ②根據統計的結果將序列回收到原來的序列中比如&#xff0c;現在有一個數組{6,1,2,9,4,2,4,1,4}。該數組中&#xff0c;元素1出現兩次&#…

深度解析 Spring Boot 循環依賴:原理、源碼與解決方案

在 Spring Boot 開發中,循環依賴是一個常見且容易被忽視的技術點。當兩個或多個 Bean 相互引用時,就會形成循環依賴(如 A 依賴 B,B 依賴 A)。初學者往往會困惑:Spring 為什么能自動處理這種看似矛盾的依賴關系?本文將從原理、源碼實現到解決方案,全方位剖析 Spring Boo…

數據庫的基本操作(約束與DQL查詢)

一、約束約束是在表上強制執行的數據規則&#xff0c;用于確保數據的完整性和一致性&#xff08;1&#xff09;約束類型MySQL中支持多種約束類型&#xff1a;①主鍵約束&#xff08;PRIMARY KEY&#xff09; ②自增約束&#xff08;AUTO_INCREMENT&#xff09;③非空約束…

HP Pavilion G6 筆記本安裝Ubuntu開機后自動進入飛行模式的問題解決

問題一臺HP Pavilion G6 筆記本 &#xff0c;安裝了Ubuntu24.04版本&#xff0c;開機后&#xff0c;直接進入飛行模式&#xff0c;導致無法使用Wifi,且使用fnf10的組合鍵&#xff0c;也無法關閉飛行模式。使用fnf10鍵&#xff0c;可以看到提示顯示飛行模式&#xff0c;但無法關…

LLM:MoE原理與實現探索

文章目錄前言一、Deepseek Moe二. Moe架構1. Expert2. Gate3. MoE Module三、Auxiliary Loss總結前言 MoE&#xff08;Mixture of Experts) 已經逐漸在LLM中廣泛應用&#xff0c;其工程部署相關目前也有了越來越多的支持&#xff0c;本文主要記錄一下MoE的基本模塊構造與原理。…

基于領域事件驅動的微服務架構設計與實踐

引言&#xff1a;為什么你的微服務總是"牽一發而動全身"&#xff1f; 在復雜的業務系統中&#xff0c;你是否遇到過這樣的困境&#xff1a;修改一個訂單服務&#xff0c;卻導致支付服務異常&#xff1b;調整庫存邏輯&#xff0c;用戶服務開始報錯。這種"蝴蝶效應…

如何使用curl編程來下載文件

libcurl 是一個功能強大的跨平臺網絡傳輸庫&#xff0c;支持多種協議。 本篇來介紹libcul的C語言編程&#xff0c;實現一個文件下載的功能。 1 curl基礎介紹 1.1 核心數據結構 1.1.1 CURL句柄 CURL是libcurl 的核心句柄&#xff0c;每個請求對應一個 CURL 實例&#xff0c;…

大語言模型提示工程與應用:ChatGPT提示工程技術指南

ChatGPT提示工程 學習目標 在本課程中&#xff0c;我們將學習更多關于ChatGPT的最新提示工程技術。 相關知識點 ChatGPT提示工程 學習內容 1 ChatGPT提示工程 ChatGPT是OpenAI研發的新型對話模型&#xff0c;具備多輪對話能力。該模型通過人類反饋強化學習(RLHF)訓練&am…