フロイドのアルゴリズムに関する個人的な洞察
最近手渡されるアルゴリズムの宿題があるので、タイトルを見てみましたが、おおよそ重み付きの最短経路でした。そこで、フロイトのアルゴリズムを考えて、百度を見て要約しました。
私たちが旅行に行く場合、私たちは間違いなく間違った方法を避けたいので、2つの場所の間の最短距離を知る必要があります。
これらの4つの場所に到達するための8つの道路があります。これらの道路は片道であることに注意してください。ここで、任意の2つの都市間の最短距離を求める必要があります。つまり、任意の2つのポイント間の最短経路を見つける必要があります。この問題は、「マルチソース最短パス」問題とも呼ばれます。
ここで、それを格納するための2次元配列が必要であり、4 * 4行列を作成できます。たとえば、都市1から都市2までの距離が2の場合、e [1] [2]は2に設定されます。 2ができない都市No.4に到達するには、e [2] [4]の値を∞に設定します。また、ここで、都市がそれ自体である場合、それも0であることに同意します。たとえば、e [1] [1]が0の場合、詳細は次のとおりです。
2点間の距離を短くしたい場合は、通過点(vertex k)を導入するだけで、距離を短くすることができます(つまり、a-> k-> b)。場合によっては、2つの通過点が必要になることもあります。さらに、ルートを短くするには、つまり、k1、k2、k3などを導入します(つまり、a-> k1-> k2 ...-> k-> i ...-> b)。上の写真、元の4-> 3ルートは12です。1パス後に4-> 1-> 3になると、距離は11になります(つまり、e [4] [1] + e [1] [3 ] = 5 + 6 = 11)。それでは、問題を一般的な状況に変えてください。
- 別のトランジットポイントを通過せずに
- トランジットポイント1
を通過し、トランジットポイント1のみを通過する場合はどうすればよいですか?e [i] [1] + e [1] [j]がe [i] [j]よりも小さいかどうかを判断するだけです。e[i] [j]は頂点iから頂点jまでの距離を意味します。e [i] [1] + e [1] [j]は、頂点iから頂点1までの距離、次に頂点1から頂点jまでの距離の合計を表します。コードは次のように実装されます。
for (i = 1; i <= n; i++)
{
for (j = 1; j <= n; j++)
{
//循环是遍历整个矩阵,判断每个点经过1是否会变小
if (e[i][j] > e[i][1] + e[1][j])
e[i][j] = e[i][1] + e[1][j];
}
}
1を通過すると、ルートテーブルが次のように更新されます。
上の図から、白でマークされた3つの場所から1を通過した後の他のポイントまでの距離が短くなっていることがわかります。
- トランジットポイント
1と2を通過した後、1と2を順番に通過するとどうなりますか?頂点No.1を通過するときに任意の2点間の最短距離を許可した結果、頂点No. 2を通過する場合、頂点iと頂点jの間の距離を短くできるかどうかを判断する必要があります。つまり、e [i] [2] + e [2] [j]がe [i] [j]よりも小さいかどうかを判断するために、コードは次のように実装されます。
//经过1号顶点
for(i=1;i<=n;i++)
{
for(j=1;j<=n;j++)
{
if (e[i][j] > e[i][1]+e[1][j]) e[i][j]=e[i][1]+e[1][j];
}
}
//经过2号顶点
for(i=1;i<=n;i++)
{
for(j=1;j<=n;j++)
{
if (e[i][j] > e[i][2]+e[2][j]) e[i][j]=e[i][2]+e[2][j];
}
}
頂点1と2のみが許可されている場合、任意の2点間の最短距離は次のように更新されます。
前の4-> 3が1の後に11に変更され(4-> 1-> 3)、 2(4-> 1-> 2-> 3)の後、10になります。
同じことが通過点1、2、および3にも当てはまり、頂点1、2、および3のみが通過を許可されるという条件の下で、任意の2点間の最短距離が見つかります。任意の2点間の最短距離が次のように更新されます。
- すべての転送ポイントの後、
すべての頂点が転送として通過
できるようになります。任意の2つのポイント間の最終的な最短距離は、次のとおりです。プロセス全体を実際には数行のコードに簡略化できます。
for(k=0; k<n ; k++){
//简单的说就是更新二维矩阵,将任何一个点经过任何一个中间点之后的路程更新为最短的距离
//一句话概括就是:从i号顶点到j号顶点只经过前k号点的最短路程。
for(i =0; i<n; i++){
for(j=0; j<n; j++){
if(e[i][j] > (e[i][k] + e[k][j])){
e[i][j] = e[i][k] + e[k][j];
}
}
}
}
上記は、すべてのトランジットポイントを通過した後の任意のポイントまでの最短距離です。簡単に言えば、最初のk点のみを通る頂点iから頂点jまでの最短距離です。