圖論理論部分

旅游完回來繼續學習。

先來看一下圖論的理論部分,然后稍微做一下DFS的題目。

圖的基本概念

二維坐標中,兩點可以連成線,多個點連成的線就構成了圖。

當然圖也可以就一個節點,甚至沒有節點(空圖)

圖的種類

整體上一般分為 有向圖 和 無向圖。

有向圖是指 圖中邊是有方向的:

?

無向圖是指 圖中邊沒有方向:

?

加權有向圖,就是圖中邊是有權值的,例如:

?

加權無向圖也是同理。

無向圖中有幾條邊連接該節點,該節點就有幾度。

例如,該無向圖中,節點4的度為5,節點6的度為3。

?

在有向圖中,每個節點有出度和入度。

出度:從該節點出發的邊的個數。

入度:指向該節點邊的個數。

例如,該有向圖中,節點3的入度為2,出度為1,節點1的入度為0,出度為2。

?

連通性

在圖中表示節點的連通情況,我們稱之為連通性。

連通圖

在無向圖中,任何兩個節點都是可以到達的,我們稱之為連通圖 ,如圖:

?

如果有節點不能到達其他節點,則為非連通圖,如圖:

?

節點1 不能到達節點4。

強連通圖

在有向圖中,任何兩個節點是可以相互到達的,我們稱之為 強連通圖。

這里有錄友可能想,這和無向圖中的連通圖有什么區別,不是一樣的嗎?

我們來看這個有向圖:

?

這個圖是強連通圖嗎?

初步一看,好像這節點都連著,但這不是強連通圖,節點1可以到節點5,但節點5不能到節點1 。

強連通圖是在有向圖中任何兩個節點是可以相互到達

下面這個有向圖才是強連通圖:

?

連通分量

在無向圖中的極大連通子圖稱之為該圖的一個連通分量。

只看概念大家可能不理解,我來畫個圖:

?

該無向圖中 節點1、節點2、節點5 構成的子圖就是 該無向圖中的一個連通分量,該子圖所有節點都是相互可達到的。

同理,節點3、節點4、節點6 構成的子圖 也是該無向圖中的一個連通分量。

那么無向圖中 節點3 、節點4 構成的子圖 是該無向圖的聯通分量嗎?

不是!

因為必須是極大聯通子圖才能是連通分量,所以 必須是節點3、節點4、節點6 構成的子圖才是連通分量。

在圖論中,連通分量是一個很重要的概念,例如島嶼問題(后面章節會有專門講解)其實就是求連通分量。

強連通分量

在有向圖中極大強連通子圖稱之為該圖的強連通分量。

如圖:

?

節點1、節點2、節點3、節點4、節點5 構成的子圖是強連通分量,因為這是強連通圖,也是極大圖。

節點6、節點7、節點8 構成的子圖 不是強連通分量,因為這不是強連通圖,節點8 不能達到節點6。

節點1、節點2、節點5 構成的子圖 也不是 強連通分量,因為這不是極大圖。

圖的構造

我們如何用代碼來表示一個圖呢?

一般使用鄰接表、鄰接矩陣 或者用類來表示。

主要是 樸素存儲、鄰接表和鄰接矩陣。

關于樸素存儲,這是我自創的名字,因為這種存儲方式,就是將所有邊存下來。

例如圖:

?

圖中有8條邊,我們就定義 8 * 2的數組,即有n條邊就申請n * 2,這么大的數組:

?

數組第一行:6 7,就表示節點6 指向 節點7,以此類推。

當然可以不用數組,用map,或者用 類 到可以表示出 這種邊的關系。

這種表示方式的好處就是直觀,把節點與節點之間關系很容易展現出來。

但如果我們想知道 節點1 和 節點6 是否相連,我們就需要把存儲空間都枚舉一遍才行。

這是明顯的缺點,同時,我們在深搜和廣搜的時候,都不會使用這種存儲方式。

因為 搜索中,需要知道 節點與其他節點的鏈接情況,而這種樸素存儲,都需要全部枚舉才知道鏈接情況。

在圖論章節的后面文章講解中,我會舉例說明的。大家先有個印象。

鄰接矩陣

鄰接矩陣 使用 二維數組來表示圖結構。 鄰接矩陣是從節點的角度來表示圖,有多少節點就申請多大的二維數組。

例如: grid[2][5] = 6,表示 節點 2 連接 節點5 為有向圖,節點2 指向 節點5,邊的權值為6。

如果想表示無向圖,即:grid[2][5] = 6,grid[5][2] = 6,表示節點2 與 節點5 相互連通,權值為6。

如圖:

?

在一個 n (節點數)為8 的圖中,就需要申請 8 * 8 這么大的空間。

圖中有一條雙向邊,即:grid[2][5] = 6,grid[5][2] = 6

這種表達方式(鄰接矩陣) 在 邊少,節點多的情況下,會導致申請過大的二維數組,造成空間浪費。

而且在尋找節點連接情況的時候,需要遍歷整個矩陣,即 n * n 的時間復雜度,同樣造成時間浪費。

鄰接矩陣的優點:

  • 表達方式簡單,易于理解
  • 檢查任意兩個頂點間是否存在邊的操作非常快
  • 適合稠密圖,在邊數接近頂點數平方的圖中,鄰接矩陣是一種空間效率較高的表示方法。

缺點:

  • 遇到稀疏圖,會導致申請過大的二維數組造成空間浪費 且遍歷 邊 的時候需要遍歷整個n * n矩陣,造成時間浪費

鄰接表

鄰接表 使用 數組 + 鏈表的方式來表示。 鄰接表是從邊的數量來表示圖,有多少邊 才會申請對應大小的鏈表。

鄰接表的構造如圖:

?

這里表達的圖是:

  • 節點1 指向 節點3 和 節點5
  • 節點2 指向 節點4、節點3、節點5
  • 節點3 指向 節點4
  • 節點4指向節點1

有多少邊 鄰接表才會申請多少個對應的鏈表節點。

從圖中可以直觀看出 使用 數組 + 鏈表 來表達 邊的連接情況 。

鄰接表的優點:

  • 對于稀疏圖的存儲,只需要存儲邊,空間利用率高
  • 遍歷節點連接情況相對容易

缺點:

  • 檢查任意兩個節點間是否存在邊,效率相對低,需要 O(V)時間,V表示某節點連接其他節點的數量。
  • 實現相對復雜,不易理解

以上大家可能理解比較模糊,沒關系,因為大家還沒做過圖論的題目,對于圖的表達沒有概念。

這里我先不給出具體的實現代碼,大家先有個初步印象,在后面算法題實戰中,我還會講到具體代碼實現,等帶大家做算法題,寫了代碼之后,自然就理解了。

圖的遍歷方式

圖的遍歷方式基本是兩大類:

  • 深度優先搜索(dfs)
  • 廣度優先搜索(bfs)

二叉樹的遞歸遍歷,是dfs 在二叉樹上的遍歷方式。

二叉樹的層序遍歷,是bfs 在二叉樹上的遍歷方式。

dfs 和 bfs 一種搜索算法,可以在不同的數據結構上進行搜索,在二叉樹章節里是在二叉樹這樣的數據結構上搜索。

而在圖論章節,則是在圖(鄰接表或鄰接矩陣)上進行搜索。

然后來看一道題目:98. 所有可達路徑

這道題需要找出所有的路徑,很明顯是一道深搜的題目。

而對于深搜的題目來講,最重要的就是搞清楚遞歸的參數,條件,終止情況

但是,由于這里是ACM模式,所以我們還需要注意數據的讀取和存儲,其實這道題存儲量不大,三種圖的存儲方式都是可以的。但是寫法也會發生變化,下面把三種方式都放出來。

鄰接矩陣寫法

#include <iostream>
#include <vector>
using namespace std;
vector<vector<int>> result; // 收集符合條件的路徑
vector<int> path; // 1節點到終點的路徑void dfs (const vector<vector<int>>& graph, int x, int n) {// 當前遍歷的節點x 到達節點n if (x == n) { // 找到符合條件的一條路徑result.push_back(path);return;}for (int i = 1; i <= n; i++) { // 遍歷節點x鏈接的所有節點if (graph[x][i] == 1) { // 找到 x鏈接的節點path.push_back(i); // 遍歷到的節點加入到路徑中來dfs(graph, i, n); // 進入下一層遞歸path.pop_back(); // 回溯,撤銷本節點}}
}int main() {int n, m, s, t;cin >> n >> m;// 節點編號從1到n,所以申請 n+1 這么大的數組vector<vector<int>> graph(n + 1, vector<int>(n + 1, 0));while (m--) {cin >> s >> t;// 使用鄰接矩陣 表示無線圖,1 表示 s 與 t 是相連的graph[s][t] = 1;}path.push_back(1); // 無論什么路徑已經是從0節點出發dfs(graph, 1, n); // 開始遍歷// 輸出結果if (result.size() == 0) cout << -1 << endl;for (const vector<int> &pa : result) {for (int i = 0; i < pa.size() - 1; i++) {cout << pa[i] << " ";}cout << pa[pa.size() - 1]  << endl;}
}

鄰接表寫法

#include <iostream>
#include <vector>
#include <list>
using namespace std;vector<vector<int>> result; // 收集符合條件的路徑
vector<int> path; // 1節點到終點的路徑void dfs (const vector<list<int>>& graph, int x, int n) {if (x == n) { // 找到符合條件的一條路徑result.push_back(path);return;}for (int i : graph[x]) { // 找到 x指向的節點path.push_back(i); // 遍歷到的節點加入到路徑中來dfs(graph, i, n); // 進入下一層遞歸path.pop_back(); // 回溯,撤銷本節點}
}int main() {int n, m, s, t;cin >> n >> m;// 節點編號從1到n,所以申請 n+1 這么大的數組vector<list<int>> graph(n + 1); // 鄰接表while (m--) {cin >> s >> t;// 使用鄰接表 ,表示 s -> t 是相連的graph[s].push_back(t);}path.push_back(1); // 無論什么路徑已經是從0節點出發dfs(graph, 1, n); // 開始遍歷// 輸出結果if (result.size() == 0) cout << -1 << endl;for (const vector<int> &pa : result) {for (int i = 0; i < pa.size() - 1; i++) {cout << pa[i] << " ";}cout << pa[pa.size() - 1]  << endl;}
}

下面是筆者自己寫的樸素存儲的方式:

#include<iostream>
#include<vector>
using namespace std;vector<vector<int>> path;
vector<int> pre_path;void dfs(vector<pair<int,int>> ab,int i,int n){if(i==n){path.push_back(pre_path);return;}for(auto pre:ab){int k=0;if(pre.first==i)    k=pre.second;pre_path.push_back(k);dfs(ab,k,n);pre_path.pop_back();}
}int main(){int n,m=0;cin>>n>>m;vector<pair<int,int>>   ab(m,{0,0});for(int i=0;i<m;i++){cin>>ab[i].first>>ab[i].second;}pre_path.push_back(1);dfs(ab,1,n);if (path.size() == 0) cout << -1 << endl;for (const vector<int> &pa : path) {for (int i = 0; i < pa.size() - 1; i++) {cout << pa[i] << " ";}cout << pa[pa.size() - 1]  << endl;}
}

OK,今天就到這

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

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

相關文章

WebSocket集群方案解析與實現

一、WebSocket集群核心挑戰 1.1 關鍵問題分析 #mermaid-svg-gzRCTMr7wiVCokct {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-gzRCTMr7wiVCokct .error-icon{fill:#552222;}#mermaid-svg-gzRCTMr7wiVCokct .error-t…

使用dify搭建hr簡歷助手-上傳簡歷-對接飛書ai表格

一、需求背景 hr在招聘平臺獲取簡歷后&#xff0c;想整理到簡歷庫&#xff0c;在線管理和維護&#xff0c;及其不方便&#xff0c;所以用dify搭建一個簡歷上傳助手&#xff0c;并且能保存到線上表格&#xff0c;方便維護和查看。 先看下最終的效果我們的工作流即可自動獲取文件…

《算法導論》第 22 章 - 基本的圖算法

大家好&#xff01;今天我們來深入學習《算法導論》第 22 章的基本圖算法。圖論是計算機科學中的重要基礎&#xff0c;這些基本算法是解決很多復雜問題的基石。本文將結合代碼實現&#xff0c;幫助大家更好地理解和應用這些算法。思維導圖22.1 圖的表示在計算機中&#xff0c;圖…

基于PROFINET的西門子PLC通訊:S7-200與S7-1200在自動化倉儲中的協同應用

一.行業痛點與解決方案傳統倉儲物流系統中&#xff0c;采用西門子SMARTS7-200PLC&#xff08;如CPUSR20、SR30等型號&#xff09;的設備往往面臨三大通訊難題&#xff1a;一是無法直接接入以太網網絡&#xff0c;導致多PLC間的數據交互需要通過復雜的串口級聯實現&#xff0c;響…

redis實現秒殺超賣問題的解決方案:(僅限于單體項目)

秒殺實現通過樂觀鎖控制超賣問題通過悲觀鎖控制每個用戶只能下一單&#xff0c;避免用戶多次點擊&#xff0c;發送的多次下單請求(即多個線程)都成功&#xff0c;避免惡意攻擊每個請求訪問Tomcat時&#xff0c;就會分配一個線程處理請求業務邏輯&#xff1a;注*以下邏輯中報錯也…

Go與Python爬蟲實戰對比:從開發效率到性能瓶頸的深度解析

目錄 引言&#xff1a;兩種語言&#xff0c;兩種哲學 開發效率對比&#xff1a;從框架設計看易用性 Python的"開箱即用" Go的"手動組裝" 性能對比&#xff1a;從并發模型看效率差異 理論性能對比 實際測試數據 錯誤處理對比&#xff1a;從編程范式…

初識c語言————排序方法

今天我們學習的是c語言中的排序方法目錄&#xff1a;一.冒泡排序法二.選擇排序法下面我們正式學習c語言中的排序方法一.冒泡排序法1.冒泡排序法的過程&#xff1a;將無序的數組通過數組之間的大小比較&#xff0c;排成有序的樣子2.例如&#xff1a;5&#xff0c;3&#xff0c;4…

爬蟲與數據分析結合案例:中國大學排名爬取與分析全流程

爬蟲與數據分析結合案例&#xff1a;中國大學排名爬取與分析全流程 一、案例背景與目標 本案例以高三網中國大學排名&#xff08;網址&#xff1a;2021中國的大學排名一覽表_高三網&#xff09;為數據源&#xff0c;完成從數據爬取到分析可視化的全流程實踐。主要目標包括&am…

行業分享丨SimSolid 在汽車零部件開發中應用的可行性調研及實踐

*本文源自汽車行業用戶范會超投稿1、背景車型短周期開發背景下&#xff0c;高效的仿真技術顯得尤為重要。Altair 推出了多款加速設計/仿真的軟件&#xff0c;其中無網格軟件 SimSolid 與業務有一定的契合度&#xff0c;有必要論證其在汽車零部件結構分析領域的可行性。2、目標評…

MacOS字體看起來比在 Windows 上更好?

字體控們注意啦&#xff01;&#x1f389;你們有沒有發現&#xff0c;同樣一段文字&#xff0c;在Mac和Windows上看起來就是不一樣&#xff1f;Mac上的字仿佛自帶柔光濾鏡&#xff0c;圓潤又舒適&#xff1b;而Windows上的字則像是精心雕琢的刀鋒&#xff0c;銳利且清晰。這背后…

Torch -- 卷積學習day1 -- 卷積層,池化層

目錄 一、CNN概述 二、卷積層 1、卷積核 2、卷積計算 3、邊緣填充 4、步長 5、多通道卷積計算 6、多卷積核卷積計算 7、特征圖大小 8、卷積參數共享 9、局部特征提取 10、卷積層API 三、池化層 1、池化層概述 1.池化層的作用 2.池化層類型 2、池化層計算 3、步…

藍橋杯---第六屆省賽單片機組真題

先出手寫的代碼&#xff0c;代碼分析還需要一段時間&#xff0c;不難&#xff0c;大家認真寫。#include <STC15F2K60S2.H> #include "Seg.h" #include "LED.h" #include "Key.h" #include "DS1302.h" #include "DS18B20.h&…

GPT-5深度解析:精準、高效、務實的新一代AI引擎

&#x1f31f; GPT-5深度解析&#xff1a;精準、高效、務實的新一代AI引擎在萬眾矚目中&#xff0c;OpenAI于2025年8月7日正式推出GPT-5——這一代模型沒有華麗的創意革命&#xff0c;卻以驚人的準確率提升、斷崖式降價和強大的工程能力&#xff0c;悄然重塑了生成式AI的應用邊…

oss(阿里云)前端直傳

WEB端前端直傳 參考文檔&#xff1a;web前端直傳并設置上傳回調 封裝oss-upload.ts // 圖片上傳 import { uploadToken } from /api/uploadFile.js // 獲取oss token接口// 定義 OSS 信息類型 interface OssInfo {policy: string;signature: string;x_oss_credential: strin…

vscode uv 發布一個python包:編輯、調試與相對路徑導包

背景 最近一直在使用uv做python包管理&#xff0c;用起來很方便。 尤其是在代碼上傳到github的時候&#xff0c;pyproject.toml 會顯示出當前項目依賴的python包。這樣在把代碼下載到本地之后&#xff0c;直接uv sync就可以很方便地恢復出python環境。 uv 除了有上述優點&…

Secure 第四天作業

實驗需求&#xff1a;需求一拓撲&#xff1a;按照以上拓撲所示&#xff0c;完成以下需求&#xff1a;參考以上拓撲&#xff0c;配置設備IP地址&#xff0c;使用UNL里Secure第四天拓撲即可。&#xff08;有興趣的同學課后也可按照PPT原拓撲做做實驗&#xff09;&#xff1b;配置…

利用開漏輸出模式模擬IIC

/************************************************************利用IO口模擬IIC時序&#xff0c;需要使用2個IO口(SDA和SCL)SCL時鐘線只能由主器件進行控制&#xff0c;所以SCL引腳必須為輸出模式SDA數據線&#xff0c;在主器件發送數據時&#xff0c;SDA引腳為輸出模式SDA數…

閘機控制系統從設計到實現全解析:第 5 篇:RabbitMQ 消息隊列與閘機通信設計

第 5 篇&#xff1a;RabbitMQ 消息隊列與閘機通信設計RabbitMQ 是一款開源的消息隊列中間件&#xff08;Message Queue&#xff0c;MQ&#xff09;&#xff0c;基于 Erlang 語言開發&#xff0c;遵循 AMQP&#xff08;Advanced Message Queuing Protocol&#xff0c;高級消息隊…

Linux 常用命令大全:覆蓋日常 99% 操作需求

1、基本命令 pwd&#xff1a;顯示當前工作目錄的絕對路徑&#xff0c;例如在復雜目錄結構中快速確認位置&#xff0c;執行后會輸出類似/home/user/documents的結果。 cd&#xff1a;切換目錄&#xff0c;cd 目錄路徑可進入指定目錄&#xff0c;cd ~回到當前用戶的家目錄&…

普通電腦與云電腦的區別有哪些?全面科普

近年來&#xff0c;越來越多的人不再購置升級自己的電腦&#xff0c;轉而選擇云電腦&#xff0c;云端產品正在變得越來越普及易用。那么它究竟跟我們的普通本地設備有什么區別吶&#xff1f;或許很多人并不知悉&#xff0c;對此&#xff0c;本篇內容小編就為大家簡要科普一下普…