最短パス(超詳細)を見つけるためのDijkstraアルゴリズムは常に更新されています

Dijkstraは最短パスを見つけます


最短経路の問題

ここに写真の説明を挿入
最初にプレーンバージョンについて話させてください

Dijkstraアルゴリズム

Dijkstraアルゴリズム(Dijkstra)は、1959年にオランダのコンピューター科学者Dijkstraによって提案されたため、Dijkstraアルゴリズムとも呼ばれます。これは、ある頂点から他の頂点への最短パスアルゴリズムであり、右のグラフの最短パスの問題を解決します。Dijkstraのアルゴリズムの主な特徴は、開始点から開始し、貪欲なアルゴリズムの戦略を採用することです。開始点に最も近く、終了点まで拡張するまでアクセスされていない頂点の隣接ノードに移動するたびに。

まず、ポイント1からポイントnまでの最短距離を見つける方法を見てみましょう。

実装プロセス

ここに写真の説明を挿入

コード
int Dijkstra()
{
    
    
    memset(dist,0x3f,sizeof dist);//除1号结点外,其他均初始为无穷大
    dist[1]=0;
    for(int i=0;i<n;i++) //n次迭代,每次寻找不在s中距离最近的点t
    {
    
    
        int t=-1;// 便于更新第一个点
        for(int j=1;j<=n;j++)
          if(!st[j]&&(t==-1||dist[j]<dist[t])) t=j;
        st[t]=true;  //将t加到s中
        for(int j=1;j<=n;j++)  //用t更新其他点的距离
          dist[j]=min(dist[j],dist[t]+g[t][j]);
    }
    if(dist[n]==0x3f3f3f3f) return -1; //路径不存在
    else return dist[n];
}

次にテンプレートを与える
ナイーブダイクストラアルゴリズムの
時間の複雑さはO(n ^ 2 + m)、nはポイントの数、mは辺の数を表します

int g[N][N];  // 存储每条边
int dist[N];  // 存储1号点到每个点的最短距离
bool st[N];   // 存储每个点的最短路是否已经确定

// 求1号点到n号点的最短路,如果不存在则返回-1
int dijkstra()
{
    
    
    memset(dist, 0x3f, sizeof dist);
    dist[1] = 0;

    for (int i = 0; i < n - 1; i ++ )
    {
    
    
        int t = -1;     // 在还未确定最短路的点中,寻找距离最小的点
        for (int j = 1; j <= n; j ++ )
            if (!st[j] && (t == -1 || dist[t] > dist[j]))
                t = j;

        // 用t更新其他点的距离
        for (int j = 1; j <= n; j ++ )
            dist[j] = min(dist[j], dist[t] + g[t][j]);

        st[t] = true;
    }

    if (dist[n] == 0x3f3f3f3f) return -1;
    return dist[n];
}

さて、テンプレートの質問を見てみましょう。練習は真実をテストするための唯一の基準です。

AcWing 849.Dijkstraは最短パスを見つけますI

n個のポイントとm個のエッジを持つ有向グラフの場合、グラフには複数のエッジと自己ループが存在する可能性があり、すべてのエッジの重みは正です。
ポイント1からポイントnまでの最短距離を見つけてください。ポイント1からポイントnまで歩くことができない場合は、-1を出力します。
入力フォーマット
最初の行には整数nとmが含まれています。
次のm行のそれぞれには、3つの整数x、y、およびzが含まれています。これは、ポイントxからポイントyに有向エッジがあり、辺の長さがzであることを示します。
出力形式
ポイント1からポイントnまでの最短距離を表す整数を出力します
パスが存在しない場合は、-1が出力されます。
データ範囲は
1≤n≤500、
1≤m≤105、
図に関与する辺の長さが10000を超えません。
入力サンプル:
3 3
1 2 2
2 3 1
1 3 4
出力サンプル:
3

完全なコード
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=510;
int g[N][N];    //稠密图用邻接矩阵存储比较节省空间
int dist[N];    //dist[i] i结点到起始点(1号结点)的距离
bool st[N] ;    //st[i] 用于标记i结点的最短路是否确定,若确定st[i]=true;
int n,m;
int Dijkstra()
{
    
    
    memset(dist,0x3f,sizeof dist);//除1号结点外,其他均初始为无穷大
    dist[1]=0;
    for(int i=0;i<n;i++) //n次迭代,每次寻找不在s中距离最近的点t
    {
    
    
        int t=-1;// 便于更新第一个点
        for(int j=1;j<=n;j++)
          if(!st[j]&&(t==-1||dist[j]<dist[t])) t=j;
        st[t]=true;  //将t加到s中
        for(int j=1;j<=n;j++)  //用t更新其他点的距离
          dist[j]=min(dist[j],dist[t]+g[t][j]);
    }
    if(dist[n]==0x3f3f3f3f) return -1; //路径不存在
    else return dist[n];
}
int main()
{
    
    
    scanf("%d%d",&n,&m);
    memset(g,0x3f,sizeof g);   //邻接矩阵的初始化,由于求的是最小值,因此初始为无穷大
    while(m--)
    {
    
    
        int x,y,z;
        scanf("%d%d%d",&x,&y,&z);
        g[x][y]=min(g[x][y],z); //重边中去取最小值
    }
    printf("%d\n",Dijkstra());
    return 0;
}

何かがわからなくても心配しないで見下ろしてください

FAQコレクション

  1. 値を割り当てるときに0x3fが問題ないのはなぜですか。memset(dist,0x3f,sizeof dist)しかし後で確認するときif(dist[n]==0x3f3f3f3f)は、if(dist[n]==0x3f)
    答えmemsetなくてはなりません。::バイトで初期化され、intには4バイトが含まれるため、初期化後の値は0x3f3f3f3fです。
  2. 答えmemset(dist,0x3f,sizeof dist)を初期化する理由:: 0x3f3f3f3f 10進数は1061109567、1e9はレベル(大きさと0x7fffffff、0x7fffffffは32ビットintの最大値を表す)であり、一般的な場合のデータは1e9より小さいため、データが無限大より大きくなることなく、無限大として使用できます。一方、一般的なデータは10 ^ 9を超えることはないため、データに無限大を追加してもオーバーフローしません(これは「無限大に有限数を加えても無限大」を満たします)。 、実際、これは非常に大きいですが、32ビットintの表現範囲を超えないため、「無限大と無限大または無限大」のニーズも満たします。
    0x3f3f3f3f+0x3f3f3f3f=21222191340x3f3f3f3f
  3. for(int i=0;i<n;i++) { t=-1 }これt-1
    答えに評価されるべき理由すべてのポイントがまだ最短距離を決定していないことがわかるたびに、このポイントまでの距離が最短ポイントになります。t = - 1それはされてst最初のポイント発見の便宜のために設定更新するには、このセットを。
  4. 最短距離をaからbに変更する方法を尋ねる場合(良い質問)
    回答:を初期化するときdist[a]=0、およびを返すときに使用されますreturn dist[b]
  5. セルフループとダブルエッジはDijkstreaのアルゴリズムに影響しますか?
    回答:自己ループは、ダイクストラのアルゴリズムのナイーブバージョンでは効果がないため、負の数でない限り、自己ループの重みは任意の数にすることができます。ヘビーエッジの場合、ヘビーエッジの最小値であるコードを使用しますg[x][y]=min(g[x][y],z)
  6. 隣接リストの代わりに隣接マトリックスをストレージに使用するのはなぜですか?
    回答:隣接マトリックスを使用するか隣接リストを使用してグラフを表すかにかかわらず、グラフがまばらなグラフであるか密なグラフであるかを判断する必要があります。密なグラフは| V |²に近いエッジ| E |の数を示し、疎なグラフは| V |²よりもはるかに小さいエッジの数| E |を示します(大きな違いがあります)。この質問は密なグラフに関するものです。明らかに、密なグラフは隣接行列ストレージを使用してスペースを節約し、その逆も同様です。

質問は継続的に更新されます。コメント欄にメッセージを残してください。

おすすめ

転載: blog.csdn.net/weixin_45629285/article/details/109406455