Dijkstra算法+堆優化【模板】


Dijkstra算法用於求解一個點到所有點的距離

例子

5 5 1(5個點 5條邊 起點為1號節點)
1 2 20(下面5行是5條邊的起點、終點與權值)
2 3 30
3 4 20
4 5 20
1 5 100

代碼

//原版Dijkstra
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
using namespace std;
int edges[10002][10002];
int dist[10002];
int visited[10002];
#define inf 0x3f3f3f3f
int n, m, s;
void Dijkstra()
{
    fill(dist, dist + n+1, inf);//dist數組初始化為inf
    dist[s] = 0;//將起點的dist設為0
    for (int i = 1; i <= n; i++)//因為從起點開始,所以執行n次
    {
        int u = -1, min = inf;
        for (int j = 1; j <= n; j++)//尋找最短邊
        {
            if (!visited[j] && dist[j] < min)
            {
                u = j; min = dist[j];
            }
        }
        if (u == -1)return;
       visited[u] = 1;//這里不能忘記 for (int j = 1; j <= n; j++)
        {
            if (!visited[j])
            {
                if (min + edges[u][j] < dist[j])
                    dist[j] = min + edges[u][j];
            }
        }
    }

}
int main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);
    cin >> n >> m >> s;
    fill(edges[0], edges[0] + 10002 * 10002, inf);//這種寫法在數據量比較大的題目中是會爆內存的
    for (int i = 1; i <= m; i++)
    {
        int a, b,c;
        cin >> a >> b >> c;
        edges[a][b] = c;
    }
    Dijkstra();
    for (int i = 1; i <= n; i++)
        printf("%s%d", i == 1 ? "" : " ", dist[i]);
}

防止爆內存Dijkstra

題目:https://www.luogu.com.cn/problem/P3371

本題目數據量

 

 

 但是還是TLE………………

於是使用vector儲存圖,詳見代碼

代碼

//改進vector版Dijkstra
#include<iostream>
#include<queue>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<vector>
using namespace std;
typedef pair<int, int> p;
//這里最好使用typedef 定義一下下面再用,如果直接vector<pair<int,int>> edges[10002];在OJ編程通不過…………
//priority_queue<pair<int, int> > qq; 
// 注意在兩個尖括號之間一定要留 空格,防止誤判



vector<p> edges[10002];
long long dist[10002];
int visited[10002];
#define inf 0x3f3f3f3f
int n, m, s;
void Dijkstra()
{
    fill(dist, dist + n+1, inf);
    dist[s] = 0;
    for (int i = 1; i <= n; i++)
    {
        int u = -1;
        long long min = inf;
        for (int j = 1; j <= n; j++)
        {
            if (!visited[j] && dist[j] < min)
            {
                u = j; min = dist[j];
            }
        }
        if (u == -1)return;
        visited[u] = 1;
        for (int j = 0; j <edges[u].size(); j++)//在以u為起點的所有邊中尋找
        {
            int vv = edges[u][j].first;//是這條邊的終點
            if (!visited[vv])
            {
                if (min + edges[u][j].second< dist[vv])
                    dist[vv] = min + edges[u][j].second;
            }
        }
    }

}
int main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);
    cin >> n >> m >> s;
    for (int i = 1; i <= m; i++)
    {
        int a, b, c;
        cin >> a >> b >> c;
        edges[a].push_back(make_pair(b, c));//使用每條邊的起始節點作為edges的index,pair里是終點與權值
    }
    Dijkstra();
    bool space = false;
    for (int i = 1; i <= n; i++)
    {
        if (visited[i])
            printf("%s%d",space==false?"":" ", dist[i]);
        else printf("%s%s", space == false ? "" : " ", "2147483647");
        space = true;
    }
}
//測試實例
//5 15 5
//2 2 270
//1 4 89
//2 1 3
//5 5 261
//5 2 163
//5 5 275
//4 5 108
//4 4 231
//3 4 213
//3 3 119
//3 1 77
//3 1 6
//2 4 83
//5 5 196
//5 5 94

//166 163 2147483647 246 0

 

Dijkstra堆優化

題目:https://www.luogu.com.cn/problem/P4779

#include<iostream>
#include<queue>
#include<algorithm>
#include<cstdio>
#include<cmath>
using namespace std;
#define maxn 100010
#define maxm 500010
#define inf 0x7fffffff
struct edge
{
    int to;//終點
    int dis;//權值
    int next;//下一條邊
    //不添加from起點,意義不大
};
struct node
{
    int dis;//權值
    int pos;//下標
    bool operator <(const node &x)const
    {
        return x.dis < dis;//從小到大排序
    }
};
edge e[maxm];
int head[maxn], dist[maxn], cnt, visited[maxn];
int n, m, s; 
priority_queue<node>q;//每次出隊的都是dis最小的,節省了(更新后再比,出現更小的再更新此類情況)消耗的時間 
void addedge(int u, int v, int w)
{
    cnt++;
    e[cnt].dis = w;
    e[cnt].to = v;
    e[cnt].next = head[u];//head[u]總是臨時存放着同起點的前一條邊,當同起點的后一條邊輸入時,把前一條邊的index賦值給這條邊的next(於是同起點的邊順序是輸入順序的反序)
    head[u] = cnt;
}
void Dijkstra()
{
    fill(dist, dist + n + 1, inf);    
    dist[s] = 0;
    q.push({ 0, s });//加入起點
    while (!q.empty())
    {
        node tmp = q.top();
        q.pop();
        int x = tmp.pos, d = tmp.dis;
        if (visited[x])continue;
        visited[x] = 1;//相當於前面的visited[u] = 1;
        for (int i = head[x]; i; i = e[i].next)
        {
            int y = e[i].to;
            if (dist[y] > dist[x] + e[i].dis)
            {
                dist[y] = dist[x] + e[i].dis;
                    q.push({ dist[y], y });
            }
        }
    }
}
int main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);
    cin >> n >> m >> s;
    for (int i = 1; i <= m; i++)
    {
        int a, b, c;
        cin >> a >> b >> c;
        addedge(a, b, c);
    }
    Dijkstra();
    for (int i = 1; i <= n; i++)
        printf("%s%d", i == 1 ? "" : " ", dist[i]);
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM