最短経路テンプレート-フロイドアルゴリズム

フロイドアルゴリズム

動的計画法のアイデアに基づく実現:
f[i, j, k]開始点iと終了点jを除いて、iからjまでのパス上の1とkの間のポイントのみを通過するすべてのパスの最短距離を表します。

1つのポイントを通過する場合もあれば、複数のポイントを通過する場合もありますが、いずれのポイントも通過しない場合もあります。

動的伝達方程式があります:f[i, j, k] = min(f[i, j, k - 1), f[i, k, k - 1] + f[k, j, k - 1]

隣接行列fを使用すると、格納された初期化エッジ情報はf[i,j,0]、i-> jが直接であり、頂点がない状態で格納されます。

f [i、j、1]を計算すると、i-> jのパスは頂点1を通過する必要がないと判断されます。選択するかどうかの2つの選択肢があり、
f [i、j、2を探すとき]、i-> jの経路は頂点1と2を通過する必要がないと判断されます。このとき、f [i、j、1]は頂点1を通過する必要のない最短経路を見つけました。 、そしてこれに基づいて、頂点2を通過するだけで済みます。それだけです。

k番目の層のf [i、j]を計算するときは、最初にk-1番目の層のすべての状態を計算する必要があります。つまり、隣接行列2次元配列fは、次のように判断されるたびに更新されます。頂点は渡されず、合計n回更新されます。
また、この更新f[i,j]は今回は使用されないことが証明できます。これは、k = jまたはk = iでない限り、使用されるたびにf[i,k]合計になるためですが、f[k,j]f [i、i] = 0と同等です。 [追加なし]に変更するため、更新の前後にデータを維持するためにアレイを開く必要はありません。

1.これには問題があります。フロイのアルゴリズムが処理しなければならないことセルフループ
フロイドアルゴリズムは、負のループを持つグラフを処理できず(セルフループの重みが負の場合、それは負のループでもあります)、セルフループの重みが正の場合、機能しません。隣接行列の主対角(自己それ自体までの距離)は0です。

k = 1の最初の更新を考えます。f[1,3]f[1,3]=f[1,1]+f[1,3]が更新されると、そのような更新が発生します。したがって、それ自体からそれ自体までの距離を0として指定する必要があります。
これは隣接行列ストレージの定義でもあります。データが自己ループのエッジを入力するとき(負の重みのループがないため、自己ループの負の重みを持つエッジは入力されず、正の数のみが入力されます)、の最小値を取ることができますこの状況を処理するためのエッジ。(重いエッジの処理)
隣接行列がナイーブダイクストラアルゴリズムでの保存に使用される場合、正の重みを持つ自己ループは効果がないため処理する必要がないため、理由を慎重に分析してください。

第二に重いエッジの処理

隣接行列格納グラフであるため、格納できるエッジは1つのみであり、重みが最小のエッジのみが格納されます。(負の重みエッジがあります)
そして主対角線は0でなければなりません。

問題に注意してください。タイトルでは負の重みループがないことが必要なため、自己ループのエッジも正である必要があります。これにより、通常のエッジと同じように扱うことができます。
最初に主対角線を0に初期化します。 、次に最小値を取ります(毎回0でなければなりません)

3.アクセシビリティの判断

f[i,j]=min(f[i,j],f[i,k]+f[k,j])、更新できる条件は、iからkが到達可能であり、kからjも到達可能であるということです。エッジの1つが到達不能である限り、それはINFであり、更新する必要はありません。f[iである必要があります。 、j] = f [i、j]
判断条件if (f[i][k]!=INF && f[k][j]!=INF)

このように、マイナス側がINFに与える影響を心配する必要はありません。到達不可能ですが、距離はINFではなく、INFよりわずかに小さくなります。

タイトル説明

n個の点とm個のエッジを持つ有向グラフが与えられると、ヘビーサイドセルフループ、エッジの重みが負の場合があります。

k個のクエリがある場合、各クエリには2つの整数xとyが含まれます。これらは、クエリのポイントxからポイントyまでの最短距離を表します。パスが存在しない場合は、「不可能」と出力します。

データ保証グラフには負の重みループはありません。

入力形式
最初の行には、3つの整数n、m、kが含まれています

次のm行では、各行に3つの整数x、y、zが含まれています。これは、点xから点yに有向エッジがあり、辺の長さがzであることを示しています。

次のk行では、各行に2つの整数xとyが含まれています。これらは、クエリポイントxとポイントyの間の最短距離を表します。

出力形式
合計k行あり、各行はクエリの結果を示す整数を出力します。クエリの2点間にパスがない場合は、「不可能」が出力されます。

データ範囲は
、1≤n≤200
1≤k≤n 2
1≤m≤20000、及び
図に関与する辺の長さの絶対値が10000を超えることはありません。

入力サンプル

3 3 2
1 2 1 // m個のエッジを入力23
2
1 3 1
2 1 //次はk個のクエリです
13

サンプル出力:

不可能
1

コード

#include <iostream>
#include <cstring>

using namespace std;
const int N=210,INF=0x3f3f3f3f;
int dp[N][N];
int n,m,num;

void floyd()
{
    
    
    for (int k=1;k<=n;k++)  更新n次dp二维表,求出i->j在最多经过n个顶点的下的最短路径
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                if (dp[i][k]!=INF && dp[k][j]!=INF) dp[i][j]=min(dp[i][j],dp[i][k]+dp[k][j]);
}

int main()
{
    
    
    scanf("%d%d%d",&n,&m,&num);
    
    memset(dp,0x3f,sizeof dp);
    for (int i=0;i<=n;i++) dp[i][i]=0; //结点编号从1到n,0行0列用不到
    int a,b,c;
    while(m--) {
    
    
        scanf("%d%d%d",&a,&b,&c);
        dp[a][b]=min(dp[a][b],c); //处理重边,自环时c必大于0,所以主对角线还是0
    }
    floyd(); 
    //然后dp数组存储任意两个点之间的最短距离
    while(num--) {
    
    
        scanf("%d%d",&a,&b);
        int t=dp[a][b];
        if (t==INF) puts("impossible");
        else printf("%d\n",t);
    }
    
    return 0;
}

おすすめ

転載: blog.csdn.net/HangHug_L/article/details/114013732