1 圖的基本操作
1.1 圖的儲存
圖儲存有兩種方法:鄰接表和鄰接矩陣。
- 鄰接表:
g[N][N] = {};
...
memset(g, 0x3f, sizeof g);
g[u][v] = w;
- 鄰接矩陣:
int head[N] = {};
memset(head, 0x3f, sizeof head);
struct edge{
int pre, to, val;
}EDGE[N];
inline void addedge(int u, int v, int w, int i){
EDGE[i] = {v, w, head[u]};
head[u] = i;
}
1.2 圖的遍歷
圖的遍歷是指從圖中的任一頂點出發,對圖中的所有頂點訪問一次且只訪問一次(訪問一次,但不止用到一次)。 圖的遍歷操作和樹的遍歷操作功能相似。
2 最短路演算法
圖求最短路有演算法:
- Floyd
- Dijkstra
- SPFA(死了)
- Bellman-Ford
- ...
2.1 Floyd
- 用途:求任意兩個結點之間的最短路
- 複雜度:\(O(n^3)\)
- 適用:適用於任何圖,不管有向無向,邊權正負,但是最短路必須存在。
for(reg int k=1; k<=n; ++k)
for(reg int i=1; i<=n; ++i)
for(reg int j=1; j<=n; ++j)
if(g[i][k] + g[k][j] < g[i][j])
g[i][j] = g[i][k]+g[k][j];
以上:g
為鄰接矩陣。
2.2 Dijkstra
- 用途:單源最短路徑
- 複雜度:\(O(n^2)\) -> \(O(nlogn)\)
- 適用:非負權圖
步驟
- 1 初始化:
源點 \(u\),dis[N]
,book[N]
。
建立集合 \(S\) 與 \(V-S\)。剛開始,只有 \(u\) 在 \(S\) 中。
vector<edge> e[MAXN];
int dis[MAXN], book[MAXN];
- 2 找
dis[]
最小:
開始,dis[n]
為 源點 \(u \rightarrow n\) 的特殊最短路。
尋找dis[n]
中最小的節點 \(t\)(可最佳化)。
- 3 加入集合 \(S\)
加入集合 \(S\),現在 \(S\) 表示為最短路的部分。
- 4 借東風
與 Floyd 較為類似,就是以一個節點 \(i\) 作中轉點,看看能不能將與周圍的節點 \(k_1, k_2, ..., k_n\) 的邊 \(k_1 \rightarrow i \rightarrow k_2\) 的長度減小(鬆弛)。
- 5 判結束
如果 \(V-S\) 集合為空集,那麼全部的dis[]
都處理完畢,這時的dis[n]
為 源點 \(u \rightarrow n\) 的最短路。
樸素演算法(沒寫過,來自 oi-wiki):
struct edge {
int v, w;
};
vector<edge> e[MAXN];
int dis[MAXN], vis[MAXN];
void dijkstra(int n, int s) {
memset(dis, 0x3f, (n + 1) * sizeof(int));
dis[s] = 0;
for (int i = 1; i <= n; i++) {
int u = 0, mind = 0x3f3f3f3f;
for (int j = 1; j <= n; j++)
if (!vis[j] && dis[j] < mind)
u = j, mind = dis[j];
vis[u] = true;
for (auto ed : e[u]) {
int v = ed.v, w = ed.w;
if (dis[v] > dis[u] + w)
dis[v] = dis[u] + w;
}
}
}
堆最佳化
堆最佳化就是用堆進行最佳化,而樸素的演算法是“掃描”一遍圖找最小的點。而小根堆優先佇列最佳化就可以快速維護最小的點,大大減少時間複雜度( \(O(nlogn)\) )。
struct edge {
int pre, to, val;
}EDGE[MAXN];
int dis[MAXN], book[MAXN], head[MAXN];
inline void addedge(int u, int v, int w, int i){
EDGE[i] = {v, w, head[u]};
head[u] = i;
}
inline void dijkstra(int s){
memset(dis, inf, sizeof dis);
priority_queue <pair<int, int>, vector<pair<int, int> >, greater<pair<int, int> > > heap;
heap.push({0, s});
while(!heap.empty()){
int t = heap.top().second;
heap.pop();
if(book[t])
continue;
book[t] = true;
for(reg int i=head[t]; i; i=EDGE[i].pre){
if(dis[EDGE[i].to] > EDGE[i].val+dis[t]){
dis[EDGE[i].to] = EDGE[i].to+dis[t];
heap.push({dis[EDGE[i].to], EDGE[i].to});
}
}
}
return;
}