1. 程式人生 > 其它 >Centos增加記憶體,配置swap交換空間

Centos增加記憶體,配置swap交換空間

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;
}