最短路

注:本篇博客的思想來自於yxc大佬的視頻講解,按照大佬的思想自己敲了一下。

樸素Dijkstra算法

題目:Dijkstra求最短路 I

題意:該題題意就是,給你一個圖,讓你求出點1到n的最短路。
思路:由於該題所有邊的權值都是正數,而且是一個稠密圖,便比較多而且,點比較少,所以比較適合樸素的Dijstra算法。時間複雜度O(n^2)。別的算法也可以,該題沒有卡spfa算法,就是哪一個稍微比較好的一點的問題。
下面是樸素Dijkstra算法,上面是spfa算法。
Refused
代碼:

#include<bits/stdc++.h>
using namespace std;

const int maxn = 510;
int mp[maxn][maxn], vis[maxn], dis[maxn];
int n, m;
void Dijstra(){
    memset(dis, 0x3f, sizeof dis);
    dis[1] = 0;
    for(int i = 1; i < n; i++){
        int index = -1;
        for(int j = 1; j <= n; j++){
          if(!vis[j] && (index == -1 || dis[index] > dis[j])){
                index = j;
          }
            
        }
        vis[index] = 1;
        for(int j = 1; j <= n; j++){
            dis[j] = min(dis[j], dis[index] + mp[index][j]);
        }
    }
    
}
int main(){
    cin>>n>>m;
    memset(mp, 0x3f, sizeof mp);
    for(int i = 1; i <= m; i++){
        int a, b, c;
        cin>>a>>b>>c;
        
        mp[a][b] = min(mp[a][b], c);
    }
    
    Dijstra();
    
    if(dis[n] == 0x3f3f3f3f)cout<<-1<<endl;
    else cout<<dis[n]<<endl;
    
    return 0;
}

堆優化Dijkstra算法

題目:Dijkstra求最短路 II

思路:本題的所有邊的權值全部爲正值,所以還可以接着用Dijkstra算法,由於點和邊的個數都是1~1e5,屬於稀疏圖,可以用堆優化的Dijkstra算法。時間複雜度O(m*log(n))
代碼:

#include<bits/stdc++.h>
using namespace std;

const int maxn = 1e5+10;
int h[maxn], tot = 0, nex[maxn], to[maxn], w[maxn];
void add(int a, int b, int c){
    to[tot] = b;
    w[tot] = c;
    nex[tot] = h[a];
    h[a] = tot++;
}
int n, m, dis[maxn], vis[maxn];
typedef  pair<int, int>  PII;
int Dijkstra(){
    memset(dis, 0x3f, sizeof dis);
    priority_queue<PII>q;
    dis[1] = 0;
    q.push({0, 1});
    
    while(q.size()){
        PII tmp = q.top();
        q.pop();
        //cout<<tmp.second<<endl;
        if(vis[tmp.second])continue;
        vis[tmp.second] = 1;
        
        for(int i = h[tmp.second]; ~i; i = nex[i]){
            int j = to[i], val = w[i];
            
            if(dis[j] > dis[tmp.second] + val){
                dis[j] = dis[tmp.second] + val;
                q.push({-dis[j], j});
            }
        }
    }
    if(dis[n] == 0x3f3f3f3f)return -1;
    else return dis[n];
    
}
int main(){
    cin>>n>>m;
    int a, b, c;
    memset(h, -1, sizeof h);
    for(int i = 1; i <= m; i++){
        cin>>a>>b>>c;
        add(a, b, c);
    }
    cout<<Dijkstra()<<endl;
    
   return 0;    
}

bellman_ford算法

題目:有邊數限制的最短路

題意:給你一個圖,讓你最多使用k條路,1~n之間的最短路,因爲存在負權值,所以需要bellman_ford算法,只能用這個算法(最短路的幾個算法)。時間複雜度O(nm)。
代碼:

#include<bits/stdc++.h>
using namespace std;

const int maxn = 1e5+10;
struct Node{
    int u, v, w;
}edge[maxn];
int n, m, k, dis[maxn], vis[maxn], backup[maxn];
void bellman_ford(){
    
    memset(dis, 0x3f, sizeof dis);
    dis[1] = 0;
    for(int  i = 1; i <= k; i++){
        memcpy(backup, dis, sizeof(dis));//防止出現串聯,就是剛更新完就用這個更新完的值去更新別的
        
        for(int j = 1; j <= m; j++){
            
            int val = edge[j].w;
            dis[edge[j].v] = min(dis[edge[j].v], backup[edge[j].u] + val);
        }
    }
    if(dis[n] > 0x3f3f3f3f/2)puts("impossible");//可能會出現這個路聯通,但是使結果小於0x3f3f3f3f但是也是非常大的數(1, 5, inf),(5, n, -100),這麼不會存在路,但是結果小於0x3f3f3f3f
    else cout<<dis[n]<<endl;
}

int main(){
    cin>>n>>m>>k;
    for(int i = 1; i <= m; i++){
        cin>>edge[i].u>>edge[i].v>>edge[i].w;
    }
    bellman_ford();
    return 0;
}

spfa算法

題目:spfa求最短路

思路:本題存在負權值,所以比較建議使用spfa算法,bellman_ford算法應該會超時的。
時間複雜度O(m)最壞O(nm)。
代碼:

#include<bits/stdc++.h>
using namespace std;

const int maxn = 1e5+10;
int h[maxn], tot = 0, nex[maxn], to[maxn], w[maxn];
void add(int a, int b, int c){
    to[tot] = b;
    w[tot] = c;
    nex[tot] = h[a];
    h[a] = tot++;
}

int n, m, dis[maxn], vis[maxn];

int spfa(){
    memset(dis, 0x3f, sizeof dis);
    queue<int>q;
    q.push(1);
    dis[1] = 0;
    vis[1] = 1;
    while(q.size()){
        int tmp = q.front();
        q.pop();
        vis[tmp] = 0;
        for(int i = h[tmp]; ~i; i = nex[i]){
            int j = to[i], val = w[i];
            if(dis[j] > dis[tmp] + val){
                dis[j] = dis[tmp] + val;
                if(!vis[j]){
                   q.push(j);
                   vis[j] = 1;
                }
            }
        }
    }
    if(dis[n] == 0x3f3f3f3f)return -1;
    else return dis[n];
    
}
int main(){
    cin>>n>>m;
    int a, b, c;
    memset(h, -1, sizeof h);
    for(int i = 1; i <= m; i++){
        cin>>a>>b>>c;
        add(a, b, c);
    }
    int t = spfa();
    if(t == -1)puts("impossible");
    else cout<<t<<endl;
    
   return 0;    
}

spfa判斷負環

題意:判斷圖中是否出現負環。
代碼:

#include<bits/stdc++.h>
using namespace std;

const int maxn = 1e5+10;
int h[maxn], tot = 0, nex[maxn], to[maxn], w[maxn];
void add(int a, int b, int c){
    to[tot] = b;
    w[tot] = c;
    nex[tot] = h[a];
    h[a] = tot++;
}

int n, m, dis[maxn], vis[maxn],cnt[maxn];

int spfa(){
    queue<int>q;
    for(int i = 1; i <= n; i++){//所有的點爲起點
        vis[i] = 1;
        q.push(i);
    }
    while(q.size()){
        int tmp = q.front();
        q.pop();
        
        vis[tmp] = 0;
        
        for(int i = h[tmp]; ~i; i = nex[i]){
            
            int j = to[i], val = w[i];
            
            if(dis[j] > dis[tmp] + val){
                
                dis[j] = dis[tmp] + val;
                cnt[j] = cnt[tmp] + 1;
                
                if(cnt[j] >= n)return true;//存在負環
                if(!vis[j]){
                   q.push(j);
                   vis[j] = 1;
                }
                
            }
        }
    }
return false;    
}
int main(){
    cin>>n>>m;
    int a, b, c;
    memset(h, -1, sizeof h);
    for(int i = 1; i <= m; i++){
        cin>>a>>b>>c;
        add(a, b, c);
    }
    int t = spfa();
    if(t == 0)puts("No");
    else puts("Yes");
    
   return 0;    
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章