日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

第三章 搜索与图论 【完结】

發布時間:2025/3/20 编程问答 17 豆豆
生活随笔 收集整理的這篇文章主要介紹了 第三章 搜索与图论 【完结】 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

以下總結摘自y總

目錄

  • DFS和BFS
  • 樹與圖的存儲
  • 樹與圖的遍歷
  • 拓撲排序
  • 樸素dijkstra算法
  • 堆優化版dijkstra
  • Bellman-Ford算法
  • spfa 算法(隊列優化的Bellman-Ford算法)
  • spfa判斷圖中是否存在負環
  • floyd算法
  • 樸素版prim算法
  • Kruskal算法
  • 染色法判別二分圖
  • 匈牙利算法 (二分圖匹配)

DFS和BFS

842. 排列數字
843. n-皇后問題
844. 走迷宮
845. 八數碼

樹與圖的存儲

樹是一種特殊的圖,與圖的存儲方式相同。
對于無向圖中的邊ab,存儲兩條有向邊a->b, b->a。
因此我們可以只考慮有向圖的存儲。

(1) 鄰接矩陣:g[a][ b ] 存儲邊a->b

(2) 鄰接表:

有向圖的鄰接表存儲就是對于每個點 v 對應一個頭節點, 記錄在h[v] idx是圖里邊的編號,和建圖的順序有關,對于某一個點v, 它的所有鄰邊的編號不一定是連續的。 e 數組是edge的縮寫,記錄了某一條有向邊的終點 ne數組是next的縮寫,記錄了鄰接表里的同一個點的下一條鄰邊的idx ne[idx]=h[a]; h[a]=idx; 就是把新建的邊插入隊頭。(先把新建的邊的next指向現在隊頭的next,然后更新隊頭的next) 然后再idx++, 給下一次建邊使用 // 對于每個點k,開一個單鏈表,存儲k所有可以走到的點。h[k]存儲這個單鏈表的頭結點 int h[N], e[N], ne[N], idx;// 添加一條邊a->b void add(int a, int b) {e[idx] = b, ne[idx] = h[a], h[a] = idx ++ ; }// 初始化 idx = 0; memset(h, -1, sizeof h);

樹與圖的遍歷

時間復雜度 O(n+m), n 表示點數,m 表示邊數
(1) 深度優先遍歷 —— 模板題 AcWing 846. 樹的重心

int dfs(int u) {st[u] = true; // st[u] 表示點u已經被遍歷過for (int i = h[u]; i != -1; i = ne[i]){int j = e[i];if (!st[j]) dfs(j);} }

(2) 寬度優先遍歷 —— 模板題 AcWing 847. 圖中點的層次

queue<int> q; st[1] = true; // 表示1號點已經被遍歷過 q.push(1);while (q.size()) {int t = q.front();q.pop();for (int i = h[t]; i != -1; i = ne[i]){int j = e[i];if (!st[j]){st[j] = true; // 表示點j已經被遍歷過q.push(j);}} }

拓撲排序

模板題 AcWing 848. 有向圖的拓撲序列
時間復雜度 O(n+m), n 表示點數,m 表示邊數

bool topsort() {int hh = 0, tt = -1;// d[i] 存儲點i的入度for (int i = 1; i <= n; i ++ )if (!d[i])q[ ++ tt] = i;while (hh <= tt){int t = q[hh ++ ];for (int i = h[t]; i != -1; i = ne[i]){int j = e[i];if (-- d[j] == 0)q[ ++ tt] = j;}}// 如果所有點都入隊了,說明存在拓撲序列;否則不存在拓撲序列。return tt == n - 1; }

樸素dijkstra算法

模板題 AcWing 849. Dijkstra求最短路 I

時間復雜是 O(n2+m), n表示點數,m 表示邊數

int g[N][N]; // 存儲每條邊 int dist[N]; // 存儲1號點到每個點的最短距離 bool st[N]; // 存儲每個點的最短路是否已經確定// 求1號點到n號點的最短路,如果不存在則返回-1 int dijkstra() {memset(dist, 0x3f, sizeof dist);dist[1] = 0;for (int i = 0; i < n - 1; i ++ ){int t = -1; // 在還未確定最短路的點中,尋找距離最小的點for (int j = 1; j <= n; j ++ )if (!st[j] && (t == -1 || dist[t] > dist[j]))t = j;// 用t更新其他點的距離for (int j = 1; j <= n; j ++ )dist[j] = min(dist[j], dist[t] + g[t][j]);st[t] = true;}if (dist[n] == 0x3f3f3f3f) return -1;return dist[n]; }

堆優化版dijkstra

模板題 AcWing 850. Dijkstra求最短路 II
時間復雜度 O(mlogn), n 表示點數,m 表示邊數

typedef pair<int, int> PII;int n; // 點的數量 int h[N], w[N], e[N], ne[N], idx; // 鄰接表存儲所有邊 int dist[N]; // 存儲所有點到1號點的距離 bool st[N]; // 存儲每個點的最短距離是否已確定// 求1號點到n號點的最短距離,如果不存在,則返回-1 int dijkstra() {memset(dist, 0x3f, sizeof dist);dist[1] = 0;priority_queue<PII, vector<PII>, greater<PII>> heap;heap.push({0, 1}); // first存儲距離,second存儲節點編號 //因為要找距離源點最近的點,而pair默認先按第一關鍵字排再按第二關鍵字排while (heap.size()){auto t = heap.top();heap.pop();int ver = t.second, distance = t.first;if (st[ver]) continue;st[ver] = true;for (int i = h[ver]; i != -1; i = ne[i]){int j = e[i];if (dist[j] > distance + w[i]) // w[i] 切記{dist[j] = distance + w[i];heap.push({dist[j], j});}}}if (dist[n] == 0x3f3f3f3f) return -1;return dist[n]; }

Bellman-Ford算法

模板題 AcWing 853. 有邊數限制的最短路
時間復雜度 O(nm), n 表示點數,m 表示邊數

上圖摘自小呆呆大神 :https://www.acwing.com/solution/content/6320/

backup就相當于,我們bfs()四個方向枚舉的時候,是用當前點枚舉的,
不能走一個方向后,用新的點接著串聯枚舉。

const int N=510; const int M=1e4+10;int n, m; // n表示點數,m表示邊數 int dist[N],backup[N]; // dist[x]存儲1到x的最短路距離struct Edge // 邊,a表示出點,b表示入點,w表示邊的權重 {int a, b, w; }edges[M];// 求1到n的最短路距離,如果無法從1走到n,則返回-1。 int bellman_ford() {memset(dist, 0x3f, sizeof dist);dist[1] = 0;// 如果第n次迭代仍然會松弛三角不等式,就說明存在一條長度是n+1的最短路徑,//由抽屜原理,路徑中至少存在兩個相同的點,說明圖中存在負權回路。for (int i = 0; i < n; i ++ ){memcpy(backup,dist,sizeof dist);for (int j = 0; j < m; j ++ ){int a = edges[j].a, b = edges[j].b, w = edges[j].w;dist[b]=min(dist[b],backup[a]+w);}}if (dist[n] > 0x3f3f3f3f / 2) return -1;return dist[n]; }

spfa 算法(隊列優化的Bellman-Ford算法)

模板題 AcWing 851. spfa求最短路
時間復雜度 平均情況下 O(m),最壞情況下 O(nm), n 表示點數,m 表示邊數
Bellman_ford算法會遍歷所有的邊,但是有很多的邊遍歷了其實沒有什么意義,
我們只用遍歷那些到源點距離變小的點所連接的邊即可,
只有當一個點的前驅結點更新了,該節點才會得到更新;
因此考慮到這一點,我們將創建一個隊列每一次加入距離被更新的結點。



上圖摘自:
小呆呆:https://www.acwing.com/solution/content/6325/
orzorz: https://www.acwing.com/solution/content/9306/

int n; // 總點數 int h[N], w[N], e[N], ne[N], idx; // 鄰接表存儲所有邊 int dist[N]; // 存儲每個點到1號點的最短距離 bool st[N]; // 存儲每個點是否在隊列中// 求1號點到n號點的最短路距離,如果從1號點無法走到n號點則返回-1 int spfa() {memset(dist, 0x3f, sizeof dist);dist[1] = 0;queue<int> q;q.push(1);st[1] = true;//標記入隊了while (q.size()){auto t = q.front();q.pop();st[t] = false;//標記出隊了for (int i = h[t]; i != -1; i = ne[i]){int j = e[i];if (dist[j] > dist[t] + w[i]){dist[j] = dist[t] + w[i];if (!st[j]) // 如果隊列中已存在j,則不需要將j重復插入{q.push(j);st[j] = true;}}}}if (dist[n] == 0x3f3f3f3f) return -1;return dist[n]; }

spfa判斷圖中是否存在負環

模板題 AcWing 852. spfa判斷負環
時間復雜度是 O(nm), n 表示點數,m 表示邊數

int n; // 總點數 int h[N], w[N], e[N], ne[N], idx; // 鄰接表存儲所有邊 int dist[N], cnt[N]; // dist[x]存儲1號點到x的最短距離,cnt[x]存儲1到x的最短路中經過的點數 bool st[N]; // 存儲每個點是否在隊列中// 如果存在負環,則返回true,否則返回false。 bool spfa() {// 不需要初始化dist數組// 原理:如果某條最短路徑上有n個點(除了自己),那么加上自己之后一共有n+1個點,由抽屜原理一定有兩個點相同,所以存在環。queue<int> q;for (int i = 1; i <= n; i ++ ){q.push(i);st[i] = true;}while (q.size()){auto t = q.front();q.pop();st[t] = false;for (int i = h[t]; i != -1; i = ne[i]){int j = e[i];if (dist[j] > dist[t] + w[i]){dist[j] = dist[t] + w[i];cnt[j] = cnt[t] + 1;if (cnt[j] >= n) return true; // 如果從1號點到x的最短路中包含至少n個點(不包括自己),則說明存在環if (!st[j]){q.push(j);st[j] = true;}}}}return false; }

floyd算法

模板題 AcWing 854. Floyd求最短路
時間復雜度是 O(n3), n 表示點數

摘自:小呆呆 https://www.acwing.com/solution/content/6337/

初始化:for (int i = 1; i <= n; i ++ )for (int j = 1; j <= n; j ++ )if (i == j) d[i][j] = 0;else d[i][j] = INF;// 算法結束后,d[a][b]表示a到b的最短距離 void floyd() {for (int k = 1; k <= n; k ++ )for (int i = 1; i <= n; i ++ )for (int j = 1; j <= n; j ++ )d[i][j] = min(d[i][j], d[i][k] + d[k][j]); }

樸素版prim算法

模板題 AcWing 858. Prim算法求最小生成樹
時間復雜度是 O(n2+m), n 表示點數,m 表示邊數

int n; // n表示點數 int g[N][N]; // 鄰接矩陣,存儲所有邊 int dist[N]; // 存儲其他點到當前最小生成樹的距離 bool st[N]; // 存儲每個點是否已經在生成樹中// 如果圖不連通,則返回INF(值是0x3f3f3f3f), 否則返回最小生成樹的樹邊權重之和 int prim() {memset(dist, 0x3f, sizeof dist);int res = 0;for (int i = 0; i < n; i ++ ){int t = -1;for (int j = 1; j <= n; j ++ )if (!st[j] && (t == -1 || dist[t] > dist[j]))t = j;if (i && dist[t] == INF) return INF; //說明不連通if (i) res += dist[t]; //第一次迭代也就是第一個點的距離不用加st[t] = true;for (int j = 1; j <= n; j ++ ) dist[j] = min(dist[j], g[t][j]);}return res; }

Kruskal算法

模板題 AcWing 859. Kruskal算法求最小生成樹
時間復雜度是 O(mlogm), n 表示點數,m 表示邊數

int n, m; // n是點數,m是邊數 int p[N]; // 并查集的父節點數組struct Edge // 存儲邊 {int a, b, w;bool operator< (const Edge &W)const{return w < W.w;} }edges[M];int find(int x) // 并查集核心操作 {if (p[x] != x) p[x] = find(p[x]);return p[x]; }int kruskal() {sort(edges, edges + m);for (int i = 1; i <= n; i ++ ) p[i] = i; // 初始化并查集int res = 0, cnt = 0;for (int i = 0; i < m; i ++ ){int a = edges[i].a, b = edges[i].b, w = edges[i].w;a = find(a), b = find(b);if (a != b) // 如果兩個連通塊不連通,則將這兩個連通塊合并{p[a] = b;res += w;cnt ++ ;}}if (cnt < n - 1) return INF;return res; }

染色法判別二分圖

模板題 AcWing 860. 染色法判定二分圖
時間復雜度是 O(n+m), n 表示點數,m 表示邊數

int n; // n表示點數 int h[N], e[M], ne[M], idx; // 鄰接表存儲圖 int color[N]; // 表示每個點的顏色,-1表示未染色,0表示白色,1表示黑色// 參數:u表示當前節點,c表示當前點的顏色 bool dfs(int u, int c) {color[u] = c;for (int i = h[u]; i != -1; i = ne[i]){int j = e[i];if (color[j] == -1){if (!dfs(j, !c)) return false; //染色沖突了}else if (color[j] == c) return false;//染色沖突了}return true; }bool check() {memset(color, -1, sizeof color);bool flag = true;for (int i = 1; i <= n; i ++ )if (color[i] == -1)if (!dfs(i, 0)){flag = false;break;}return flag; }

匈牙利算法 (二分圖匹配)

模板題 AcWing 861. 二分圖的最大匹配
時間復雜度是 O(nm), n 表示點數,m 表示邊數

int n1, n2; // n1表示第一個集合中的點數,n2表示第二個集合中的點數 int h[N], e[M], ne[M], idx; // 鄰接表存儲所有邊,匈牙利算法中只會用到從第一個集合指向第二個集合的邊,所以這里只用存一個方向的邊 int match[N]; // 存儲第二個集合中的每個點當前匹配的第一個集合中的點是哪個 bool st[N]; // 表示第二個集合中的每個點是否已經被遍歷過bool find(int x) {for (int i = h[x]; i != -1; i = ne[i]){int j = e[i];if (!st[j]){st[j] = true;if (match[j] == 0 || find(match[j])){match[j] = x;return true;}}}return false; }// 求最大匹配數,依次枚舉第一個集合中的每個點能否匹配第二個集合中的點 int res = 0; for (int i = 1; i <= n1; i ++ ) {memset(st, false, sizeof st);if (find(i)) res ++ ; }

總結

以上是生活随笔為你收集整理的第三章 搜索与图论 【完结】的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 国产一区2| 一级全黄裸体片 | 青青在线播放 | 福利在线免费观看 | 99久久免费精品 | 亚洲视频四区 | 美女av影院| 国产高潮又爽又无遮挡又免费 | 精品欧美一区二区三区 | а天堂中文在线官网 | 亚洲男人天堂影院 | 二三区视频| 曰批又黄又爽免费视频 | 亚洲九九 | 动漫av在线播放 | 2022av在线| 中文字幕在线播出 | 成 人免费va视频 | 国产3级| 动漫涩涩免费网站在线看 | 成人午夜精品一区二区三区 | 无码成人精品区在线观看 | 天天碰天天干 | 色偷偷噜噜噜亚洲男人的天堂 | 中文字幕高清av | gav成人| 台湾佬美性中文娱乐 | 99热国产在线观看 | a级黄色一级片 | 日本人妻不卡一区二区三区中文字幕 | 色婷婷91 | 色欲色香天天天综合网www | 毛片高清免费 | 一级二级三级黄色片 | 亚洲AV无码成人国产精品色 | 日韩在线小视频 | 一区二区三区偷拍 | 我不卡av| www.黄色| 亚洲第一页中文字幕 | wwwxxoo| 一级片一区 | 欧美一区二区三区色 | 大尺度做爰呻吟62集 | 成人精品一区二区三区中文字幕 | 天天操天天操天天干 | 一区二区高清 | 国产视频一区二区在线观看 | 亚洲精品国产精品乱码不99热 | 成人精品福利视频 | 美女黄色大片 | 神马久久久久久久 | 青青草原国产在线观看 | 欧美丰满艳妇bbwbbw | 一二三av| 日本精品一二三区 | 视频丨9l丨白浆 | 亚洲aⅴ在线观看 | 亚洲香蕉中文网 | 国产视频一区在线观看 | 午夜伦情 | 国产黄色片在线 | 久久久国产精品成人免费 | 欧美成人精品在线观看 | 我要操婊| 女人下面无遮挡 | 综合九九 | 国产乱码一区二区三区在线观看 | 兄弟兄弟全集免费观看 | 青青草免费观看 | av网站大全在线观看 | 伊人影院亚洲 | av亚洲在线观看 | 精品久久久久久一区二区里番 | 日本不卡网站 | 超碰加勒比 | 国产在线传媒 | 国产亚洲女人久久久久毛片 | 18禁一区二区| 日本不卡一 | 亚洲一区二区在线免费 | 成人a视频 | 在线观看黄 | 午夜福利电影 | 日本理论中文字幕 | 绯色av一区 | 另类一区二区 | 喷水视频在线观看 | 黄色天堂 | 黄色一级网| 日韩午夜伦 | 日本免费不卡一区二区 | 精品人妻aV中文字幕乱码色欲 | 韩国三级中文字幕hd久久精品 | 我的好妈妈在线观看 | 亚洲91在线 | 91porn九色 | 少妇毛片视频 | 国产毛片久久久久久国产毛片 |