多源BFS——AcWing 173. 矩陣距離

多源BFS

定義

多源BFS(多源廣度優先搜索)是一種圖遍歷算法,它是標準BFS(廣度優先搜索)的擴展,主要用于解決具有多個起始節點的最短路徑問題。在多源BFS中,不是從單一源點開始搜索整個圖,而是同時從多個源點出發,尋找這些源點到圖中所有其他節點的最短路徑。這種方法特別適用于邊權都為1的情況,如在網格圖中計算點到點的最短曼哈頓距離或歐幾里得距離。

多源BFS通過初始化一個隊列,將所有源節點放入隊列中開始。算法執行標準的BFS過程,但每次從隊列中取出一個節點進行擴展時,會檢查這個節點是否已經被訪問過,以避免重復處理。每個節點的距離是從其最近的源節點測量的,并且維護一個數據結構(如二維數組或字典)來存儲每個節點的最短距離。

運用情況

  1. 網格圖中的最短距離:例如,在一個由0和1組成的矩陣中,0表示可以通過的路徑,1表示障礙,多源BFS可以用來找出每個位置到最近的0的距離。
  2. 社交網絡中的影響力傳播:在社交網絡中,如果要計算一個人發布的信息經過多個人傳播后能影響到的最遠節點,可以將初始發布者作為多個源點進行多源BFS。
  3. 游戲地圖探索:在某些游戲中,玩家可能從多個入口進入迷宮或地圖,多源BFS可以用來快速找到各個入口到所有可到達點的最短路徑。

注意事項

  1. 標記已訪問:確保每個節點只被訪問一次,避免循環和重復計算。
  2. 初始化源節點的距離:源節點到自身的距離應初始化為0,非源節點的距離可以初始化為無窮大或一個表示未訪問的特殊值。
  3. 使用合適的數據結構:為了高效地管理待訪問節點和已訪問節點的信息,選擇適當的數據結構(如隊列、集合、字典等)至關重要。
  4. 剪枝:在某些情況下,可以通過剪枝策略提前終止不必要的搜索路徑,以優化性能。

解題思路

  1. 初始化:將所有源節點加入隊列,并初始化所有節點的距離(源節點為0,其余為無窮大或特殊值)。
  2. 遍歷:執行BFS循環,直到隊列為空。每次循環從隊列頭部取出一個節點,檢查其鄰居節點。
  3. 更新距離:對于當前節點的每個未訪問鄰居,計算從源點通過當前節點到達該鄰居的距離,如果這個距離比已知的最短距離更短,則更新該鄰居的距離,并將其加入隊列。
  4. 終止條件:當隊列為空時,所有可達節點的最短距離都已被計算。

AcWing 173. 矩陣距離

題目描述

173. 矩陣距離 - AcWing題庫

運行代碼

#include <iostream>
#include <cstring>
#define x first
#define y second
using namespace std;
typedef pair<int, int> PII;
const int N = 1010;int n, m;
char g[N][N];
PII q[N * N];
int dist[N][N];void bfs()
{int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};int hh = 0, tt = -1;for(int i = 1; i <= n; i ++ )for(int j = 1; j <= m; j ++ )if(g[i][j] == '1'){dist[i][j] = 0;q[++ tt] = {i, j};}while(hh <= tt){PII t = q[hh ++];for(int i  =0; i < 4; i ++ ){int a = t.x + dx[i], b = t.y + dy[i];if(a <= 0 || a > n || b <= 0 || b > m) continue;if(dist[a][b] != -1) continue;dist[a][b] = dist[t.x][t.y] + 1;q[++ tt] = {a, b};}}
}int main()
{memset(dist, -1, sizeof dist);cin >> n >> m;for(int i = 0; i < n; i ++ ) cin >> g[i + 1] + 1;bfs();for(int i = 1; i <= n; i ++ ){for(int j = 1; j <= m; j ++ ) cout << dist[i][j] << ' ';cout << endl;}return 0;
}

代碼思路

  1. 數據結構定義與常量設置:
    • 使用PII(pair<int, int>)類型來表示二維網格中的坐標。
    • dx[]dy[]數組分別存儲了四個基本方向的橫縱坐標增量,用于遍歷鄰居節點。
    • N定義了網格的最大尺寸,這里設為1010。
  2. 變量初始化:
    • 讀取網格的行數n和列數m
    • 通過cin讀取二維字符矩陣g,'1'代表源點,假設其他位置默認為'0'(雖然代碼中未直接處理'0'的情況,但邏輯上是這樣理解的)。
    • 使用memset將距離矩陣dist初始化為-1,表示尚未訪問。
  3. 廣度優先搜索(BFS)實現:
    • 遍歷矩陣,將所有值為'1'的點作為起點,其距離設為0,并將它們的坐標存入隊列q
    • 開始BFS過程:從隊列中取出一個點,檢查它的四個鄰居(上、下、左、右),若鄰居坐標在矩陣范圍內且尚未訪問過(dist[a][b] == -1),則更新鄰居的距離為當前點的距離加1,并將鄰居加入隊列。這一步確保了從所有源點出發,逐步擴展到整個網格,同時計算每個點到最近源點的距離。
  4. 結果輸出:遍歷二維數組dist,按照網格的行列順序輸出每個位置的最短距離,每個數字后面跟一個空格,每行結束后換行打印。

改進思路

  1. 代碼注釋和文檔:雖然代碼邏輯相對清晰,但增加更多的注釋說明每個主要步驟的作用、邊界條件處理的原因以及算法的核心思想,可以提高代碼的可讀性和可維護性。

  2. 異常處理和輸入驗證:在實際應用中,增加對輸入數據的校驗是非常重要的。比如,可以檢查nm的范圍是否合理,以及輸入矩陣是否符合預期格式,以避免運行時錯誤。

  3. 空間優化:雖然本代碼的空間復雜度已經是線性的,但考慮到在極端情況下(如矩陣幾乎全為'1')隊列q可能會占用大量內存,可以考慮在BFS過程中直接從當前層節點擴展到下一層,而不是將所有節點都存入隊列,這樣可以減少隊列的最大容量需求。

  4. 并行化處理:如果面對的是非常大的矩陣,可以考慮使用多線程或多進程并行執行BFS,每個線程負責處理一部分源點或區域,以加速計算過程。但這需要引入線程同步機制來避免數據競爭問題。

  5. 使用STL容器:雖然數組在性能上通常有優勢,但考慮到代碼的靈活性和易讀性,可以考慮使用STL容器如vector<vector<int>>來代替二維數組distg,特別是當矩陣大小不固定或需要動態調整時。

  6. 常量表達式和類型別名:可以進一步利用C++特性,比如將方向數組定義為constexpr以提高效率,或者使用using Grid = vector<vector<char>>;來定義一個類型別名,使得代碼更加現代和清晰。

  7. 宏替換為內聯函數或常量:盡管宏定義在本代碼中簡化了訪問pair成員的操作,但使用內聯函數或const變量可以提供更好的類型安全性和調試信息。

改進代碼

#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>
#include <limits>
using namespace std;// 方向向量,表示上下左右四個方向
constexpr array<pair<int, int>, 4> directions = {{{-1, 0}, {0, 1}, {1, 0}, {0, -1}}};// 使用vector替代數組以支持動態大小和更現代的C++實踐
using Grid = vector<vector<char>>;
using pii = pair<int, int>; // 簡化pair<int, int>的寫法int n, m;
Grid g;
vector<vector<int>> dist;
queue<pii> q;// BFS函數,計算每個點到最近'1'的距離
void bfs() {while (!q.empty()) {auto [cx, cy] = q.front(); q.pop();for (const auto& [dx, dy] : directions) {int nx = cx + dx, ny = cy + dy;if (nx >= 0 && nx < n && ny >= 0 && ny < m && g[nx][ny] != '1' && dist[nx][ny] == -1) {dist[nx][ny] = dist[cx][cy] + 1;q.push({nx, ny});}}}
}int main() {cin >> n >> m;g.resize(n, vector<char>(m));dist.assign(n, vector<int>(m, -1)); // 初始化距離矩陣為-1// 讀取矩陣for (int i = 0; i < n; ++i) {for (int j = 0; j < m; ++j) {cin >> g[i][j];// 將所有的'1'點加入隊列,并初始化其距離為0if (g[i][j] == '1') {dist[i][j] = 0;q.push({i, j});}}}bfs(); // 執行BFS// 輸出結果for (const auto& row : dist) {for (int d : row) {cout << (d != -1 ? d : 0) << ' '; // 如果是-1,表示不可達,輸出0}cout << endl;}return 0;
}

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

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

相關文章

怎么把webp格式轉換成jpg?5個圖片格式轉換方法全面解析(2024最新)

webp 圖片常用于網站&#xff0c;可顯著改善頁面的瀏覽和加載體驗。然而&#xff0c;許多設備&#xff08;如蘋果手機設備、安卓手機等&#xff09;不支持webp文件。在這些設備上查看webp文件時&#xff0c;最佳做法是將其轉換為其他常見格式&#xff0c;如jpg或 png。Windows電…

LeetCode 69. x 的平方根

更多題解盡在 https://sugar.matrixlab.dev/algorithm 每日更新。 組隊打卡&#xff0c;更多解法等你一起來參與哦&#xff01; LeetCode 69. x 的平方根 &#xff0c;難度簡單。 暴力 解題思路&#xff1a;直接遍歷平方 i&#xff0c; 判斷 x 是否滿足 i 2 ≤ x < ( i …

2024上海大學生程序設計競賽I-六元組計數原根知識詳解

以前基本沒有了解原根相關的一塊內容&#xff0c;最近正好碰到了這個題&#xff0c;于是寫一篇博客記錄一下。 這道題的總體思路就是比較明顯&#xff0c;就是先算出 a p x a^px apx對于每個 x x x的解的個數&#xff0c;然后NTT算一下即可。 先來講一下怎么求歐拉函數 ? ( …

前端FCP指標優化

優化前 第三方依賴按需引入之后&#xff0c;打包的總體積減小到初始值的55%&#xff0c;但是依然存在很大的js文件&#xff0c;需要繼續優化 chunk-vendors.js進行分包之后 截圖 compression-webpack-plugin壓縮之后 截圖

簡單制作基礎的Python鏡像

拉取基礎鏡像 以Ubuntu24示例 docker pull ubuntu:24.04 啟動 docker run -it -d --name ubuntu24 ubuntu:24.04 進入docker docker exec -it ubuntu24 /bin/bash 更新依賴 apt update apt full-upgrade 安裝pip 會自動安裝python3.11.7 apt install pip 支持中文…

55、Flink 中使用 Java Lambda 表達式詳解

1&#xff09;概述 1.注意 Flink 支持對 Java API 的所有算子使用 Lambda 表達式&#xff0c;但是&#xff0c;當 Lambda 表達式使用 Java 泛型時&#xff0c;需要 顯式 地聲明類型信息。 2.示例和限制 示例&#xff1a; map() 函數使用 Lambda 表達式計算輸入值的平方。 …

大學新生人工智能學習路線規劃

1. 引言 七月來臨&#xff0c;各省高考分數已揭榜完成。而高考的完結并不意味著學習的結束&#xff0c;而是新旅程的開始。對于有志于踏入IT領域的高考少年們&#xff0c;這個假期是開啟探索IT世界的絕佳時機。作為該領域的前行者和經驗前輩&#xff0c;我愿意為準新生們提供一…

基于Hadoop平臺的電信客服數據的處理與分析③項目開發:搭建基于Hadoop的全分布式集群---任務10:Hive安裝部署

任務描述 任務內容為安裝并配置在Hadoop集群中使用Hive。 任務指導 Hive是一個基于Hadoop的數據倉庫框架&#xff0c;在實際使用時需要將元數據存儲在數據庫中 具體安裝步驟如下&#xff1a; 1. 安裝MySQL數據庫&#xff08;已安裝&#xff09; 2. 解壓縮Hive的壓縮包 3…

剪映 v5.5 Pro Vip解鎖版:使用指南與注意事項

摘要&#xff1a;本文介紹了剪映Pro VIP解鎖版的使用方法&#xff0c;包括安裝、測試和使用VIP素材的步驟&#xff0c;以及如何避免誤報和保持解鎖狀態的建議。 正文&#xff1a; 剪映Pro是一款廣受歡迎的視頻編輯軟件&#xff0c;提供了豐富的視頻編輯功能和大量高質量的素材…

發送微信消息和文件

參考&#xff1a;https://www.bilibili.com/video/BV1S84y1m7xd 安裝&#xff1a; pip install PyOfficeRobotimport PyOfficeRobotPyOfficeRobot.chat.send_message(who"文件傳輸助手", message"你好&#xff0c;我是PyOfficeRobot&#xff0c;有什么可以幫助…

RabbitMQ中java實現隊列和交換機的聲明

java實現隊列和交換機的聲明 在之前我們都是基于RabbitMQ控制臺來創建隊列、交換機。但是在實際開發時&#xff0c;隊列和交換機是程序員定義的&#xff0c;將來項目上線&#xff0c;又要交給運維去創建。那么程序員就需要把程序中運行的所有隊列和交換機都寫下來&#xff0c;…

【PYG】 PyTorch中size方法和屬性

在 PyTorch 中&#xff0c;size 方法和屬性用于獲取張量的維度信息。下面是它們的用法和區別&#xff1a; node_features.size&#xff1a; 這是一個屬性&#xff08;attribute &#xff09;&#xff0c;返回一個 torch.Size 對象&#xff0c;表示張量的維度。這是不可調用的&a…

用MySQL+node+vue做一個學生信息管理系統(一):配置項目

先用npm init -y生成配置文件 在項目下新建src文件夾&#xff0c;app.js文件。src目錄用來放靜態資源文件&#xff0c;app.js是服務器文件&#xff0c;index.js是vue的入口文件 使用npm install express下載express框架 在app.js文件夾開啟node服務&#xff0c;監聽的端口為…

C++ //練習 14.29 為什么不定義const版本的遞增和遞減運算符?

C Primer&#xff08;第5版&#xff09; 練習 14.29 練習 14.29 為什么不定義const版本的遞增和遞減運算符&#xff1f; 環境&#xff1a;Linux Ubuntu&#xff08;云服務器&#xff09; 工具&#xff1a;vim 解釋&#xff1a; 遞增和遞減要改變對象本身&#xff0c;const類…

Go語言--運算符

算術運算符 關系運算符 不能寫0<a<10&#xff0c;要判斷必須0<a&&a<10。因為int和bool不兼容 邏輯運算符 位運算符 賦值運算符 其他 運算符的優先級

AcWing 1254:找樹根和孩子

【題目來源】https://www.acwing.com/problem/content/1256/【題目描述】 給定一棵樹&#xff0c;輸出樹的根root&#xff0c;孩子最多的結點max以及他的孩子。【輸入格式】 第一行&#xff1a;n&#xff0c;m&#xff0c;表示樹的節點數和邊數。 以下m行&#xff1a;每行兩個結…

浮點數在內存中的存儲結構

浮點數在內存中的存儲可以參考《IEEE754標準》https://people.eecs.berkeley.edu/~wkahan/ieee754status/IEEE754.PDF 參考博文&#xff1a;IEEE754詳解&#xff08;最詳細簡單有趣味的介紹&#xff09;-CSDN博客 單精度float占內存4字節&#xff0c;最高位bit31表示符號位&…

國家海岸線變化評估:新英格蘭和中大西洋沿岸海岸線的歷史變化

National Assessment of Shoreline Change: Historical Shoreline Change along the New England and Mid-Atlantic Coasts 國家海岸線變化評估&#xff1a;新英格蘭和中大西洋沿岸海岸線的歷史變化 摘要 海灘侵蝕是美國許多公海沿岸的一個長期問題。隨著沿岸人口的不斷增加…

永輝超市購物卡有什么用?

感覺現在在超市買東西&#xff0c;還不如網購 這不&#xff0c;端午的時候&#xff0c;朋友送的永輝卡&#xff0c;一直沒時間去用&#xff0c;我總擔心過期 但是去了超市后&#xff0c;又不知道買什么&#xff0c;最后空手而歸 還好收卡云可以回收永輝卡&#xff0c;兩張三…

《C++20設計模式》適配器模式經驗分享

文章目錄 一、前言二、對于接口的討論三、實現1、對象適配器1.1 UML類圖1.2 實現 2、類適配器 四、最后 一、前言 從適配器模式開始就是類的組合聚合&#xff0c;類與類之間結構性的問題了。 適配器模式解決的問題&#xff1a; 適配器模式能夠在不破壞現有系統結構的情況下&a…