代碼隨想錄算法訓練營 Day61 圖論ⅩⅠ Floyd A※ 最短路徑算法

圖論

題目

97. 小明逛公園
本題是經典的多源最短路問題。
在這之前我們講解過,dijkstra樸素版、dijkstra堆優化、Bellman算法、Bellman隊列優化(SPFA) 都是單源最短路,即只能有一個起點。
而本題是多源最短路,即求多個起點到多個終點的多條最短路徑。
Floyd 算法對邊的權值正負沒有要求,都可以處理
Floyd算法核心思想是動態規劃。
例如我們再求節點1 到節點9 的最短距離,用二維數組來表示即:grid[1][9],如果最短距離是10 ,那就是 grid[1][9] = 10
那節點1 到節點9 的最短距離是不是可以由節點1 到節點5的最短距離 + 節點5到節點9的最短距離組成呢?即 grid[1][9] = grid[1][5] + grid[5][9]
節點1 到節點5的最短距離是不是可以有節點1 到節點3的最短距離 + 節點3 到節點5 的最短距離組成呢? 即 grid[1][5] = grid[1][3] + grid[3][5]
以此類推,節點1 到節點3的最短距離可以由更小的區間組成。
那么這樣我們是不是就找到了,子問題推導求出整體最優方案的遞歸關系呢。
是不是 要選一個最小的,畢竟是求最短路。此時我們已經接近明確遞歸公式了。之前在講解動態規劃的時候,給出過動規五部曲:
- 確定dp數組(dp table)以及下標的含義
- 確定遞推公式
- dp數組如何初始化
- 確定遍歷順序
- 舉例推導dp數組
具體講解
1. Dp 數組表示當前節點 i 到節點 j 以 [1,...,k] 集合節點為中間節點的最短距離grid[i][j][k] = m
節點i 到 節點j 的最短距離為m,這句話可以理解,但 以[1...k]集合為中間節點就理解不了。
節點i 到節點j 的最短路徑中一定是經過很多節點,那么這個集合用[1...k] 來表示。
你可以反過來想,節點i 到節點j 中間一定經過很多節點,那么你能用什么方式來表述中間這么多節點呢?所以這里的k不能單獨指某個節點,k 一定要表示一個集合,即 [1...k] ,表示節點1 到節點k 一共k個節點的集合。
2. 確定遞推公式,我們分兩種情況:
1. 節點i 到節點j 的最短路徑經過節點k
2. 節點i 到節點j 的最短路徑不經過節點k
對于第一種情況,grid[i][j][k] = grid[i][k][k - 1] + grid[k][j][k - 1]
節點i 到節點k 的最短距離是不經過節點k,中間節點集合 [1...k-1],表示為 grid[i][k][k - 1]
節點k 到 節點j 的最短距離也是不經過節點k,中間節點集合[1...k-1],表示為 grid[k][j][k - 1]
第二種情況,grid[i][j][k] = grid[i][j][k - 1]
如果節點i 到 節點j的最短距離 不經過節點k,中間節點集合[1...k-1],表示為 grid[i][j][k - 1]
因為我們是求最短路,對于這兩種情況自然是取最小值。
即: grid[i][j][k] = min(grid[i][k][k - 1] + grid[k][j][k - 1], grid[i][j][k - 1])
3. Dp 數組初始化
grid[i][j][k] = m,表示 節點i 到 節點j 以[1...k] 集合為中間節點的最短距離為m。
剛開始初始化k 是不確定的。例如題目中只是輸入邊(節點2 -> 節點6,權值為3),那么grid[2][6][k] = 3,k需要填什么呢?把k 填成1,那如何上來就知道 節點2 經過節點1 到達節點6的最短距離是多少 呢。所以 只能 把k 賦值為 0,本題 節點0 是無意義的,節點是從1 到 n。
這樣我們在下一輪計算的時候,就可以根據 grid[i][j][0] 來計算 grid[i][j][1],此時的 grid[i][j][1] 就是節點i 經過節點1 到達節點j 的最小距離了。
grid數組是一個三維數組,那么我們初始化的數據在 i 與 j 構成的平層,如圖:在這里插入圖片描述

有初始化代碼

vector<vector<vector<int>>> grid(n + 1, vector<vector<int>>(n + 1, vector<int>(n + 1, 10005)));  // C++定義了一個三位數組,10005是因為邊的最大距離是10^4for(int i = 0; i < m; i++){cin >> p1 >> p2 >> val;grid[p1][p2][0] = val;grid[p2][p1][0] = val; // 注意這里是雙向圖
} 

grid數組中其他元素數值應該初始化多少呢?
本題求的是最小值,所以輸入數據沒有涉及到的節點的情況都應該初始為一個最大數。
這樣才不會影響,每次計算去最小值的時候 初始值對計算結果的影響。
所以grid數組的定義可以是:

// C++寫法,定義了一個三位數組,10005是因為邊的最大距離是10^4
vector<vector<vector<int>>> grid(n + 1, vector<vector<int>>(n + 1, vector<int>(n + 1, 10005)));  
  1. 遍歷順序
    從遞推公式:grid[i][j][k] = min(grid[i][k][k - 1] + grid[k][j][k - 1], grid[i][j][k - 1]) 可以看出,我們需要三個for循環,分別遍歷i,j 和k

而 k 依賴于 k - 1, i 和j 的到 并不依賴與 i - 1 或者 j - 1 等等。
那么這三個for的嵌套順序應該是什么樣的呢?我們來看初始化,我們是把 k =0 的 i 和j 對應的數值都初始化了,這樣才能去計算 k = 1 的時候 i 和 j 對應的數值。這就好比是一個三維坐標,i 和j 是平層,而k 是垂直向上的。遍歷的順序是從底向上一層一層去遍歷。所以遍歷k 的for循環一定是在最外面,這樣才能一層一層去遍歷。如圖:
其他情況:[代碼隨想錄](https://www.programmercarl.com/ka其他情況:
5. 打印 dp 數組

#include <iostream>
#include <vector>
#include <list>using namespace std;int main() {int n, m, x, y, val;cin >> n >> m;// 構建dp數組 最大邊距離為nvector<vector<vector<int>>> grid(n+1, vector<vector<int>>(n+1, vector<int>(n+1, 10001)));// 初始化dp數組for (int i = 0; i < m; ++i) {cin >> x >> y >> val;grid[x][y][0] = val;grid[y][x][0] = val;}// foryd開始for (int k = 1; k <= n; ++k) {for (int i = 1; i <= n; ++i) {for (int j = 1; j <= n; j++) {// 遞推公式grid[i][j][k] = min(grid[i][j][k-1], grid[i][k][k-1] + grid[k][j][k-1]);}}}// 輸出結果int q, start, end;cin >> q;while (q--) {cin >> start >> end;if (grid[start][end][n] == 10001) cout << -1 << endl;else cout << grid[start][end][n] << endl;}
}// 空間優化版本
#include <iostream>
#include <vector>using namespace std;int main() {int n, m, x, y, val;cin >> n >> m;// 使用二維數組更新 dp數組定義表明x到y直接距離最近的路徑點vector<vector<int>> grid(n+1, vector<int>(n+1, 10001));// 初始化dp數組for (int i = 0; i < m; ++i) {cin >> x >> y >> val;grid[x][y] = val;grid[y][x] = val;}// forydfor (int k = 1; k <= n; ++k) {for (int i = 1; i <= n; ++i) {for (int j = 1; j<= n; ++j) {// 遞推公式grid[i][j] = min(grid[i][j], grid[i][k] + grid[k][j]);}}}int q, start, end;cin >> q;while (q--) {cin >> start >> end;if (grid[start][end] == 10001) cout << -1 << endl;else cout << grid[start][end] << endl;}
}#include <iostream>
#include <vector>using namespace std;int main() {int n, m, x, y, val;cin >> n >> m;// 使用二維數組更新 dp數組定義表明x到y直接距離最近的路徑點vector<vector<int>> grid(n+1, vector<int>(n+1, 10001));// 初始化dp數組for (int i = 0; i < m; ++i) {cin >> x >> y >> val;grid[x][y] = val;grid[y][x] = val;}// forydfor (int k = 1; k <= n; ++k) {for (int i = 1; i <= n; ++i) {for (int j = 1; j<= n; ++j) {// 遞推公式grid[i][j] = min(grid[i][j], grid[i][k] + grid[k][j]);}}}int q, start, end;cin >> q;while (q--) {cin >> start >> end;if (grid[start][end] == 10001) cout << -1 << endl;else cout << grid[start][end] << endl;}
}

感悟
將每個點作為中間點去更新
127. 騎士的攻擊
本題可以使用廣度優先搜索,每次有 8 種行動路徑,帶入廣度優先搜索,但是廣搜會超時
Astar 是一種 廣搜的改良版。 有的是 Astar是 dijkstra 的改良版。
其實只是場景不同而已 我們在搜索最短路的時候, 如果是無權圖(邊的權值都是1) 那就用廣搜,代碼簡潔,時間效率和 dijkstra 差不多 (具體要取決于圖的稠密)
如果是有權圖(邊有不同的權值),優先考慮 dijkstra。
而 Astar 關鍵在于啟發式函數,也就是影響廣搜或者 dijkstra 從容器(隊列)里取元素的優先順序。
以下,我用BFS版本的A * 來進行講解。
BFS中,我們想搜索,從起點到終點的最短路徑,要一層一層去遍歷 =
而使用 Astar 算法其搜索過程是這樣的,如圖,圖中著色的都是我們要遍歷的點在這里插入圖片描述

大家可以發現 **BFS 是沒有目的性的 一圈一圈去搜索, 而 A * 是有方向性的去搜索**。
看出 A * 可以節省很多沒有必要的遍歷步驟。	那么 A * 為什么可以有方向性的去搜索,它的如何知道方向呢?**其關鍵在于 啟發式函數**。
那么啟發式函數落實到代碼處,如果指引搜索的方向?
int m=q.front();q.pop();
int n=q.front();q.pop();

從隊列里取出什么元素,接下來就是從哪里開始搜索。所以 啟發式函數 要影響的就是隊列里元素的排序
如何影響元素的選擇?
對隊列里節點進行排序,就需要給每一個節點權值,如何計算權值呢?
每個節點的權值為F,給出公式為:F = G + H
G:起點達到目前遍歷節點的距離
H:目前遍歷的節點到達終點的距離
起點達到目前遍歷節點的距離 + 目前遍歷的節點到達終點的距離 = 起點到達終點的距離。
本題的圖是無權網格狀,在計算兩點距離通常有如下三種計算方式:
1. 曼哈頓距離,計算方式:d = abs(x1-x2)+abs(y1-y2)
2. 歐氏距離(歐拉距離) ,計算方式:d = sqrt( (x1-x2)^2 + (y1-y2)^2 )
3. 切比雪夫距離,計算方式:d = max(abs(x1 - x2), abs(y1 - y2))
x1, x2 為起點坐標,y1, y2 為終點坐標,abs 為求絕對值,sqrt 為求開根號,
選擇哪一種距離計算方式也會導致 A * 算法的結果不同。
可以使用 優先級隊列 幫我們排好序,每次出隊列,就是F最小的節點。
實現代碼如下:(啟發式函數采用歐拉距離計算方式)

#include <iostream>
#include <vector>
#include <queue>
#include <cstring>using namespace std;// 棋盤網格大小
int moves[1001][1001];
// 可以走的方向
int dir[8][2] = {-1,2,-2,1,-2,-1,-1,-2,1,-2,2,-1,2,1,1,2};
int b1, b2;// F = G + H
// G = 從起點到該節點路徑消耗
// H = 該節點到終點的預估消耗struct Knight {int x,y;int g,h,f;bool operator< (const Knight& k) const {return k.f < f;}
};priority_queue<Knight> que;// 歐拉距離公式
int Eular(const Knight& k) {return (k.x - b1) * (k.x - b1) + (k.y - b2) * (k.y - b2);
}void Astar(const Knight& k) {Knight cur, next;que.push(k);while (!que.empty()) {cur = que.top();que.pop();if (cur.x == b1 && cur.y == b2) break;for (int i = 0; i < 8; ++i) {next.x = cur.x + dir[i][0];next.y = cur.y + dir[i][1];if (next.x < 1 || next.x > 1000 || next.y < 1 || next.y > 1000) continue;if (!moves[next.x][next.y]) {moves[next.x][next.y] = moves[cur.x][cur.y] + 1;// 計算F next.g = cur.g + 5; // 5 走日 1*1 + 2*2next.h = Eular(next);next.f = next.g + next.h;que.push(next);}}}
}int main() {int n, a1, a2;cin >> n;while (n--) {cin >> a1 >> a2 >> b1 >> b2;memset(moves, 0, sizeof(moves));Knight start;start.x = a1;start.y = a2;start.g = 0;start.h = Eular(start);start.f = start.g + start.h;Astar(start);while (!que.empty()) que.pop();cout << moves[b1][b2] << endl;}return 0;
}

Astar 缺點
大家看上述 A * 代碼的時候,可以看到我們想隊列里添加了很多節點,但真正從隊列里取出來的僅僅是靠啟發式函數判斷距離終點最近的節點。
相對了普通BFS,A * 算法只從隊列里取出距離終點最近的節點。那么問題來了,A * 在一次路徑搜索中,大量不需要訪問的節點都在隊列里,會造成空間的過度消耗。
IDA * 算法對這一空間增長問題進行了優化,關于 IDA * 算法,本篇不再做講解,感興趣的錄友可以自行找資料學習。
另外還有一種場景是 A * 解決不了的。
如果題目中,給出多個可能的目標,然后在這多個目標中選擇最近的目標,這種 A * 就不擅長了, A * 只擅長給出明確的目標然后找到最短路徑。
如果是多個目標找最近目標(特別是潛在目標數量很多的時候),可以考慮 Dijkstra ,BFS 或者 Floyd。

圖論總結

深度優先搜索廣度優先搜索

在二叉樹章節中,其實我們講過了 深搜和廣搜在二叉樹上的搜索過程。
在圖論章節中,深搜與廣搜就是在圖這個數據結構上的搜索過程。
深搜與廣搜是圖論里基本的搜索方法,大家需要掌握三點:

  • 搜索方式:深搜是可一個方向搜,不到黃河不回頭。 廣搜是圍繞這起點一圈一圈的去搜。
  • 代碼模板:需要熟練掌握深搜和廣搜的基本寫法。
  • 應用場景:圖論題目基本上可以即用深搜也可用廣搜,無疑是用哪個方便而已

并查集

并查集相對來說是比較復雜的數據結構,其實他的代碼不長,但想徹底學透并查集,需要從多個維度入手,我在理論基礎篇的時候 講解如下重點:

  • 為什么要用并查集,怎么不用個二維數據,或者set、map之類的。
  • 并查集能解決那些問題,哪些場景會用到并查集
  • 并查集原理以及代碼實現
  • 并查集寫法的常見誤區
  • 帶大家去模擬一遍并查集的過程
  • 路徑壓縮的過程
  • 時間復雜度分析

上面這幾個維度 大家都去思考了,并查集基本就學明白了。
其實理論基礎篇就算是給大家出了一道裸的并查集題目了,所以在后面的題目安排中,會稍稍的拔高一些,重點在于并查集的應用上。
例如 并查集可以判斷這個圖是否是樹,因為樹的話,只有一個根,符合并查集判斷集合的邏輯,題目:0108.冗余連接。
在 0109.冗余連接II 中對有向樹的判斷難度更大一些,需要考慮的情況比較多。

最小生成樹

最小生成樹是所有節點的最小連通子圖, 即:以最小的成本(邊的權值)將圖中所有節點鏈接到一起。
最小生成樹算法,有prim 和 kruskal。
prim 算法是維護節點的集合,而 Kruskal 是維護邊的集合
在 稀疏圖中,用Kruskal更優。 在稠密圖中,用prim算法更優。

邊數量較少為稀疏圖,接近或等于完全圖(所有節點皆相連)為稠密圖

Prim 算法 時間復雜度為 O(n^2),其中 n 為節點數量,它的運行效率和圖中邊樹無關,適用稠密圖。
Kruskal算法 時間復雜度 為 O(nlogn),其中n 為邊的數量,適用稀疏圖。
關于 prim算法,我自創了三部曲,來幫助大家理解

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

大家只要理解這三部曲, prim算法 至少是可以寫出一個框架出來,然后在慢慢補充細節,這樣不至于 自己在寫prim的時候 兩眼一抹黑 完全憑感覺去寫。
minDist數組 是prim算法的靈魂,它幫助 prim算法完成最重要的一步,就是如何找到 距離最小生成樹最近的點
kruscal的主要思路:

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

而判斷節點是否在一個集合 以及將兩個節點放入同一個集合,正是并查集的擅長所在。
所以 Kruskal 是需要用到并查集的。

拓撲排序

拓撲排序 是在圖上的一種排序。
概括來說,給出一個 有向圖,把這個有向圖轉成線性的排序 就叫拓撲排序
同樣,拓撲排序也可以檢測這個有向圖 是否有環,即存在循環依賴的情況。
拓撲排序的一些應用場景,例如:大學排課,文件下載依賴 等等。
只要記住如下兩步拓撲排序的過程,代碼就容易寫了:

  1. 找到入度為0 的節點,加入結果集
  2. 將該節點從圖中移除

最短路徑總結

至此已經講解了四大最短路算法,分別是 Dijkstra、Bellman_ford、SPFA 和 Floyd。
針對這四大最短路算法,我用了七篇長文才徹底講清楚,分別是:

  • Dijkstra 樸素版
  • Dijkstra 堆優化版
  • Bellman_ford
  • Bellman_ford 隊列優化算法(又名 SPFA)
  • Bellman_ford 算法判斷負權回路
  • Bellman_ford 之單源有限最短路
  • Floyd 算法精講
  • 啟發式搜索:A * 算法
    在這里插入圖片描述

這里我給大家一個大體使用場景的分析:
如果遇到單源且邊為正數,直接 Dijkstra
至于 使用樸素版還是堆優化版還是取決于圖的稠密度,多少節點多少邊算是稠密圖,多少算是稀疏圖,這個沒有量化,如果想量化只能寫出兩個版本然后做實驗去測試,不同的判題機得出的結果還不太一樣。
一般情況下,可以直接用堆優化版本。
如果遇到單源邊可為負數,直接 Bellman-Ford,同樣 SPFA 還是 Bellman-Ford 取決于圖的稠密度。
一般情況下,直接用 SPFA。
如果有負權回路,優先 Bellman-Ford,如果是有限節點最短路也優先 Bellman-Ford,理由是寫代碼比較方便。如果是遇到多源點求最短路,直接 Floyd
除非源點特別少,且邊都是正數,那可以多次 Dijkstra 求出最短路徑,但這種情況很少,一般出現多個源點了,就是想讓你用 Floyd 了。
對于 A * ,由于其高效性,所以在實際工程應用中使用最為廣泛,由于其結果的不唯一性,也就是可能是次短路的特性,一般不適合作為算法題。
游戲開發、地圖導航、數據包路由等都廣泛使用 A * 算法。

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

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

相關文章

【機器學習】集成學習與梯度提升決策樹

目錄 一、引言 二、自舉聚合與隨機森林 三、集成學習器 四、提升算法 五、Python代碼實現集成學習與梯度提升決策樹的實驗 六、總結 一、引言 在機器學習的廣闊領域中,集成學習(Ensemble Learning)猶如一座閃耀的明星,它通過組合多個基本學習器的力量,創造出…

yarn、pnpm、npm

非常好&#xff0c;這樣從“問題驅動 → 工具誕生 → 優化演進”的角度來講&#xff0c;更清晰易懂。下面我按時間線和動機&#xff0c;把 npm → yarn → pnpm 的演變脈絡講清楚。 &#x1f9e9; 一、npm 為什么一開始不夠好&#xff1f; 早期&#xff08;npm v4 及之前&…

如何用AI寫作?

過去半年&#xff0c;我如何用AI高效寫作&#xff0c;節省數倍時間 過去六個月&#xff0c;我幾乎所有文章都用AI輔助完成。我的朋友——大多是文字工作者&#xff0c;對語言極為敏感——都說看不出我的文章是AI寫的還是親手創作的。 我的AI寫作靈感部分來自丘吉爾。這位英國…

什么是trace,分布式鏈路追蹤(Distributed Tracing)

在你提到的 “個人免費版” 套餐中&#xff0c;“Trace 上報量&#xff1a;5 萬條 / 月&#xff0c;存儲 3 天” 里的 Trace 仍然是指 分布式鏈路追蹤記錄&#xff0c;但需要結合具體產品的場景來理解其含義和限制。以下是更貼近個人用戶使用場景的解釋&#xff1a; 一、這里的…

[免費]微信小程序網上花店系統(SpringBoot后端+Vue管理端)【論文+源碼+SQL腳本】

大家好&#xff0c;我是java1234_小鋒老師&#xff0c;看到一個不錯的微信小程序網上花店系統(SpringBoot后端Vue管理端)【論文源碼SQL腳本】&#xff0c;分享下哈。 項目視頻演示 【免費】微信小程序網上花店系統(SpringBoot后端Vue管理端) Java畢業設計_嗶哩嗶哩_bilibili 項…

PyTorch——DataLoader的使用

batch_size, drop_last 的用法 shuffle shuffleTrue 各批次訓練的圖像不一樣 shuffleFalse 在第156step順序一致

【Linux】基礎文件IO

&#x1f31f;&#x1f31f;作者主頁&#xff1a;ephemerals__ &#x1f31f;&#x1f31f;所屬專欄&#xff1a;Linux 前言 無論是日常使用還是系統管理&#xff0c;文件是Linux系統中最核心的概念之一。對于初學者來說&#xff0c;理解文件是如何被創建、讀取、寫入以及存儲…

【JAVA后端入門基礎001】Tomcat 是什么?通俗易懂講清楚!

&#x1f4da;博客主頁&#xff1a;代碼探秘者 ?專欄&#xff1a;《JavaSe》 其他更新ing… ??感謝大家點贊&#x1f44d;&#x1f3fb;收藏?評論?&#x1f3fb;&#xff0c;您的三連就是我持續更新的動力?? &#x1f64f;作者水平有限&#xff0c;歡迎各位大佬指點&…

TDengine 的 AI 應用實戰——電力需求預測

作者&#xff1a; derekchen Demo數據集準備 我們使用公開的UTSD數據集里面的電力需求數據&#xff0c;作為預測算法的數據來源&#xff0c;基于歷史數據預測未來若干小時的電力需求。數據集的采集頻次為30分鐘&#xff0c;單位與時間戳未提供。為了方便演示&#xff0c;按…

D2000平臺上Centos使用mmap函數遇到的陷阱

----------原創不易&#xff0c;歡迎點贊收藏。廣交嵌入式開發的朋友&#xff0c;討論技術和產品------------- 在飛騰D2000平臺上&#xff0c;安裝了麒麟linux系統&#xff0c;我寫了個GPIO點燈的程序&#xff0c;在應用層利用mmap函數將內核空間映射到用戶態&#xff0c;然后…

深入了解linux系統—— 進程間通信之管道

前言 本篇博客所涉及到的代碼一同步到本人gitee&#xff1a;testfifo 遲來的grown/linux - 碼云 - 開源中國 一、進程間通信 什么是進程間通信 在之前的學習中&#xff0c;我們了解到了進程具有獨立性&#xff0c;就算是父子進程&#xff0c;在修改數據時也會進行寫時拷貝&…

設計模式——模版方法設計模式(行為型)

摘要 模版方法設計模式是一種行為型設計模式&#xff0c;定義了算法的步驟順序和整體結構&#xff0c;將某些步驟的具體實現延遲到子類中。它通過抽象類定義模板方法&#xff0c;子類實現抽象步驟&#xff0c;實現代碼復用和算法流程控制。該模式適用于有固定流程但部分步驟可…

Python使用

Python學習&#xff0c;從安裝&#xff0c;到簡單應用 前言 Python作為膠水語言在web開發&#xff0c;數據分析&#xff0c;網絡爬蟲等方向有著廣泛的應用 一、Python入門 相關基礎語法直接使用相關測試代碼 Python編譯器版本使用3以后&#xff0c;安裝參考其他教程&#xf…

吳恩達機器學習筆記(1)—引言

目錄 一、歡迎 二、機器學習是什么 三、監督學習 四、無監督學習 一、歡迎 機器學習是當前信息技術領域中最令人興奮的方向之一。在這門課程中&#xff0c;你不僅會學習機器學習的前沿知識&#xff0c;還將親手實現相關算法&#xff0c;從而深入理解其內部機理。 事實上&…

java筆記08

多線程&JUC 1.什么是多線程 1.什么是多線程&#xff1f;有了多線程&#xff0c;我們就可以讓程序同時做多件事情 2.多線程的作用&#xff1f;提高效率 3.多線程的應用場景&#xff1f;只要你想讓多個事情同時運行就需要用到多線程比如&#xff1a;軟件中的耗時操作、所有…

【仿muduo庫實現并發服務器】使用正則表達式提取HTTP元素

使用正則表達式提取HTTP元素 1.正則表達式2.正則庫的使用3.使用正則表達式提取HTTP請求行 1.正則表達式 正則表達式它其實是描述了一種字符串匹配的模式&#xff0c;它可以用來在一個字符串中檢測一個特定格式的字串&#xff0c;以及可以將符合特定規則的字串進行替換或者提取…

顯示即戰略:鐵電液晶如何成為 “數字中國” 的 “像素基石”?

一、顯示技術&#xff1a;數字時代的核心戰略支點 &#xff08;一&#xff09;從 “視覺窗口” 到 “戰略基礎設施” 在數字經濟蓬勃發展的當下&#xff0c;顯示技術早已超越了單純的 “視覺呈現” 范疇&#xff0c;成為連接人與數字世界的關鍵接口。從智能手機、平板電腦到車…

適合小白的超詳細配置YOLOv8教程(畢設必看)(訓練自己數據集)(Pycharm保姆級安裝教程)(lablme的使用)(GPU版)

目錄 1.Pycharm的安裝和虛擬環境調用&#xff08;已經安裝好的可以跳過此步驟&#xff09; 1.1 下載pycharm軟件 1.2 調用已創建虛擬環境&#xff08;調用上一篇教程中創建好的虛擬環境&#xff09; 2.標注自己數據集&#xff08;已有數據集的這部分可跳過&#xff09; 2.1…

EC800X QuecDuino開發板介紹

支持的模組列表 EG800KEC800MEC800GEC800E 功能列表 基本概述 EC800X QuecDuino EVB 搭載移遠 EC800 系列模組。支持模組型號為&#xff1a; EC800M 系列、EC800K 系列、EG800K 系列、EC800E 系列等。 渲染圖 開發板的主要組件、接口布局見下圖 資料下載 EC800X-QuecDui…

Unity + HybirdCLR熱更新 入門篇

官方文檔 HybridCLR | HybridCLRhttps://hybridclr.doc.code-philosophy.com/docs/intro 什么是HybirdCLR? HybridCLR&#xff08;原名 huatuo&#xff09;是一個專為 Unity 項目設計的C#熱更新解決方案&#xff0c;它通過擴展 IL2CPP 運行時&#xff0c;使其支持動態加載和…