鏈式前向星
一種儲存圖的資料結構
建立一個結構體和一個陣列加一個變數,這裡的to代表邊\((u,v)\)中的\(v\)結點,而\(edge\)陣列的索引\(idx\)代表\(u\),其中\(w\)代表權值,\(next\)代表以\(u\)為起始點的上一個邊。
\(head\)代表這個\(x\)結點在\(edge\)陣列中的最後一個邊的下標索引,\(cnt\)用於記錄邊時當\(edge\)的下標索引用。
struct {
int to, w, next;
} edge[MAX_N];
int head[MAX_N], cnt = 0;
為鏈式前向星新增邊
++cnt
為新新增的邊選擇一個空變數edge[++cnt].next=head[u]
代表讓\(edge[cnt]\)中的\(next\)變數指向\(u\)結點的上一個邊- \(head[u]=cnt\)代表更新結點\(u\)的最後一條邊在\(edge\)中的下標
edge[++cnt].next=head[u];
edge[cnt].w=w;
edge[cnt].to=v;
head[u]=cnt;
遍歷
首先獲取結點\(x\)的最後一條邊,經過資料處理後,將i移向結點\(x\)的上一條邊
for(int i=head[x];i;i=edge[i].next)
SPFA演算法
求最小單源路徑
- 將源點放入佇列中,並標誌源點\(s\)已經在佇列之中\(vis[s]=true\)
- 進入一個迴圈,當佇列為空,各節點的最短路徑便求出來了
- 從佇列中取出一個結點,並更新標誌,遍歷該結點的邊,對符合條件的各邊\(dis[edge[i].to]>dis[v]+edge[i].w\)進行鬆弛,然後如果符合條件的鬆弛邊目標結點如果未在佇列中,則放入,更改標誌。
鬆弛:對於每個頂點v∈V,都設定一個屬性\(d[v]\),用來描述從源點s到v的最短路徑上權值的上界,稱為最短路徑估計。就是這個操作\(dis[edge[i].to] = dis[v] + edge[i].w;\)
queue<int> que;
que.emplace(s);
vis[s] = true;
while (!que.empty()) {
int v = que.front();
que.pop();
vis[v] = false;
for (int i = head[v]; i; i = edge[i].next) {
if (dis[v] + edge[i].w < dis[edge[i].to]) {
dis[edge[i].to] = dis[v] + edge[i].w;
if (!vis[edge[i].to]) {
que.emplace(edge[i].to);
vis[edge[i].to] = true;
}
}
}
}
求是否存在負環
如果一個圖存在負環,那麼其的最短路徑一定會存在一個無限迴圈,經過負環後,路徑越來越小,那麼一定有一些結點,一直入隊出隊,判斷是否有結點入隊次數大於\(n\)次
queue<int> que;
que.emplace(1);
vis[1]=true,dis[1]=0;
while (!que.empty()) {
int v = que.front();
que.pop();
vis[v] = false;
fe(ver, G[v]) if (dis[ver.to] > dis[v] + ver.cost) {
dis[ver.to] = dis[v] + ver.cost;
if (!vis[ver.to]) {
if (++cnt[ver.to] >= n) {
//存在負環
}
que.emplace(ver.to);
vis[ver.to] = true;
}
}
}