Centos增加記憶體,配置swap交換空間
阿新 • • 發佈:2021-01-14
SPFA演算法
由BellmanFord演算法進行優化得來的
當BellmanFord演算法 遍歷所有邊的時候 dis[b]=min[dis[b],dis[a]+c];
這個表示式只有dis[a]變小的時候才可能變小。
SPFA 既可以判斷負環也可以判斷無負環的
所以SPFA將dis[a]變小的點加入佇列,並更新他們所連線的邊,可以省去無用的迭代
核心操作
1.先將1點入隊
2.將dis[a]變小的節點放入佇列中
3.取出隊頭->t 把隊頭刪掉 用t更新以t為起點的邊
4.更新成功後把b加入佇列,判斷,如果佇列中有b則不加入
#include<bits/stdc++.h> using namespace std; const int N = 1e5 + 10; const int M = 1e5 + 10; int n, m, h[N], e[M], ne[M], wei[M], vis[N], dis[N], idx; void add(int a, int b, int c) { e[idx] = b; wei[idx] = c; //有權重時,用鄰接表儲存圖,在圖中加入一條邊 ne[idx] = h[a]; h[a] = idx++; } int SPFA() { memset(dis, 0x3f, sizeof(dis));//初始化距離 dis[1] = 0; queue<int> q; //定義佇列 SPFA優化 佇列中儲存的是邊權重減小的邊 只有前驅減小了,他的後繼才有可能減小 q.push(1); vis[1] = 1; while (q.size()) { int now = q.front(); q.pop(); vis[now] = false;// 由於SPFA中存在負權邊 所有可重複加入 此初與Dijkstra不同,由於Dijkstra 所有邊權為正,所以最短路不會經過一個點兩次 for (int i = h[now]; i != -1; i=ne[i]) {//核心操作,在邊權重減小的邊中,更新他的後繼變小的邊, int j = e[i]; if (dis[j] > dis[now] + wei[i]) { dis[j] = dis[now] + wei[i]; if (!vis[j]) {//如果這個點被更新了且不在佇列中,則把他加入佇列 q.push(j); } } } } if (dis[n] == 0x3f3f3f3f)// 當佇列為空時,SPFA演算法已經幫我們找到了到n點的最短路徑 return -1; else return dis[n]; } int main() { memset(h, -1, sizeof(h)); cin >> n >> m; for (int i = 1; i <= m; i++) { int a, b, c; cin >> a >> b >> c; add(a, b, c); } if (SPFA() == -1) { cout << "impossible" << endl; } else cout << SPFA() << endl; return 0; }
SPFA判負環
dis[x] : 表示當前 1~x的最短距離
cnt[x]: 表示當前最短路的邊數
更新
dis[x]=dis[t]+w[i];
cnt[x]=cnt[t]+1; //從1x的邊數=從1t的邊數+1
如果cnt[x]>=n 意味著從1 到x 至少經過了n條邊 ->至少經過了n+1個點->則存在環
因為每次更新路徑都是在減少,所以環一定是負環
#include<bits/stdc++.h> using namespace std; const int N = 1e5 + 10; const int M = N * 2; int n, m, h[N], e[M], ne[M], wei[M], vis[N], dis[N], cnt[N], idx; //dis[N]代表到這個點的距離 cnt[N] 代表走到這個點經歷了多少邊 void add(int a, int b, int c) { e[idx] = b; wei[idx] = c; ne[idx] = h[a]; h[a] = idx++; } bool SPFA_Negative() { queue<int> q; for (int i = 1; i <= n; i++) { q.push(i); vis[1] = 1; //從1號點可能走不到負環 所以從多個起點開始 } while (q.size()) { int now = q.front(); q.pop(); vis[now] = 0; for (int i = h[now]; i != -1; i = ne[i]) { int j = e[i]; if (dis[j] > dis[now] + wei[i]) { dis[j] = dis[now] + wei[i]; cnt[j] = cnt[now] + 1;//更新邊的距離的時候把cnt也更新 if (cnt[j] >= n) return true;//如果到某個點經歷了大於n個點 則說明存在自環 因為距離都是往短了更新 所以存在負環 if (!vis[j]) { q.push(j); vis[j] = 1; } } } } return false; } int main() { memset(h, -1, sizeof(h)); cin >> n >> m; for (int i = 1; i <= m; i++) { int a, b, c; cin >> a >> b >> c; add(a, b, c); } if (SPFA_Negative()) cout << "Yes" << endl; else cout << "No" << endl; return 0; }