定義
フロイドの最短距離アルゴリズムも、図4に与えられたソースマルチ加重アルゴリズムとの間の最短経路を見つけるための動的プログラミングの概念を用いて、補間点として知られている(フロイド最短パスアルゴリズム)法。
原則
私たちの目標は、jは点から点への最短経路を見つけることが私です。
iは最短経路のjはノードに任意のノードから可能な2を超えません。
①直接私からjへ。
②IからJの複数を介して、kはノードに。
オーダーディス(i、j)がiは最短経路のJをノードからノードへの距離です。
各ノードkのために、我々は、ディス(I、K)+ディス(k、j)は<ディス(i、j)は確立されている、または確立された場合、ディス(i、j)はディス(I、K)+ディスし=チェック(K、J)。
我々はすべてのノードkをトラバースされてあれば、ディス(i、j)はjへの最短経路Iに記録された距離です。
❗フロイトは負の重み付きグラフを扱うことができません。
1-> 3最短経路、1-> 2-> 3-> 1-> 2-> 3-> 1-> 2-> 3を求めている場合......この場合は、無限ループに陥ります。
実現
#include <ビット/ STDC ++ H>
使用して 名前空間STDを、
const int型 MAXN = 1005 ;
const int型 INF = 0x3f3f3f3f 。
INTのN、M、E [MAXN] [MAXN]。
空フロイド();
int型のmain()
{
int型I、U、V、W;
フィル(E [ 0 ]、E [ 0 ] + MAXN * MAXN、INF)。
用(i = 0 ; I <MAXN; iは++)E [i]は[I] = 0 ;
scanf関数(" %d個の%のD "、&N、&M)。
用(i = 1 ; I <= M; iは++ )
{
scanf関数(" %D%D%D "、およびuは、&V、およびW)
E [U] [V] = Wは、
}
フロイド();
システム(「一時停止」)。
リターン 0 ;
}
空フロイド()
{
int型I、J、K。
用(K = 1 ++ k個; kは<= N )
のための(i = 1 ; iが<= N; iが++ )
のために(J = 1 ; J <= N; J ++ )
場合(E [I]、[J]> E [I] [K] + E [K] [J])
そして[I] [J] = E [I] [K] + 及び[K] [J]。
}
スプレッド
レコードのパス
コード1
#include<bits/stdc++.h>
using namespace std;
const int maxn=1005;
const int inf=0x3f3f3f3f;
int n,m,e[maxn][maxn],path[maxn][maxn],ans[maxn],top=-1;
void floyd();
void print(int x,int y);
int main()
{
int i,u,v,w;
fill(e[0],e[0]+maxn*maxn,inf);
for(i=0;i<maxn;i++) e[i][i]=0;
scanf("%d%d",&n,&m);
for(i=1;i<=m;i++)
{
scanf("%d%d%d",&u,&v,&w);
e[u][v]=w;
}
floyd();
scanf("%d%d",&u,&v);
ans[++top]=u;
print(u,v);
ans[++top]=v;
for(i=0;i<=top;i++)
printf("%d%s",ans[i],i==top?"\n":"->");
system("pause");
return 0;
}
void print(int x,int y)
{
if(!path[x][y]) return;
print(x,path[x][y]);
ans[++top]=path[x][y];
print(path[x][y],y);
}
void floyd()
{
int i,j,k;
for(k=1;k<=n;k++)
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(e[i][j]>e[i][k]+e[k][j])
{
e[i][j]=e[i][k]+e[k][j];
path[i][j]=k;
}
}
代码2
#include<bits/stdc++.h>
using namespace std;
const int maxn=1005;
const int inf=0x3f3f3f3f;
int n,m,e[maxn][maxn],path[maxn][maxn];
void floyd();
void print(int x,int y);
int main()
{
int i,u,v,w;
fill(e[0],e[0]+maxn*maxn,inf);
for(i=0;i<maxn;i++) e[i][i]=0;
for(i=0;i<maxn;i++)
for(int j=0;j<maxn;j++)
path[i][j]=j;
scanf("%d%d",&n,&m);
for(i=1;i<=m;i++)
{
scanf("%d%d%d",&u,&v,&w);
e[u][v]=w;
}
floyd();
scanf("%d%d",&u,&v);
print(u,v);
system("pause");
return 0;
}
void print(int x,int y)
{
if(x==y)
{
printf("%d",y);
return ;
}
int k=path[x][y];
printf("%d-->",x);
print(k,y);
}
void floyd()
{
int i,j,k;
for(k=1;k<=n;k++)
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(e[i][j]>e[i][k]+e[k][j])
{
e[i][j]=e[i][k]+e[k][j];
path[i][j]=path[i][k];
}
}
找环
有向图和无向图的环是不同的,有向图中至少2个就可以成环,而无向图中至少需要3个顶点才能成环。
有向图
#include<bits/stdc++.h>
using namespace std;
const int maxn=1005;
const int inf=0x3f3f3f3f;
int n,m,e[maxn][maxn];
void floyd();
int main()
{
int i,u,v,w,ans=inf;
fill(e[0],e[0]+maxn*maxn,inf);
scanf("%d%d",&n,&m);
for(i=1;i<=m;i++)
{
scanf("%d%d%d",&u,&v,&w);
e[u][v]=w;
}
floyd();
for(i=1;i<=n;i++) ans=min(ans,e[i][i]);
printf("%d\n",ans);
system("pause");
return 0;
}
void floyd()
{
int i,j,k;
for(k=1;k<=n;k++)
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(e[i][j]>e[i][k]+e[k][j])
e[i][j]=e[i][k]+e[k][j];
}
无向图
#include<bits/stdc++.h>
using namespace std;
const int maxn=1005;
const int inf=999999;
int n,m,e[maxn][maxn],ve[maxn][maxn];
void floyd();
int main()
{
int i,u,v,w;
fill(e[0],e[0]+maxn*maxn,inf);
fill(ve[0],ve[0]+maxn*maxn,inf);
for(i=0;i<maxn;i++) e[i][i]=ve[i][i]=0;
scanf("%d%d",&n,&m);
for(i=1;i<=m;i++)
{
scanf("%d%d%d",&u,&v,&w);
ve[u][v]=e[u][v]=w;
ve[v][u]=e[v][u]=w;
}
floyd();
system("pause");
return 0;
}
void floyd()
{
int MinCost=inf;
for(int k=1;k<=n;k++)
{
for(int i=1;i<k;i++) //更新k点之前枚举ij求经过ijk的最小环
for(int j=i+1;j<k;j++)
MinCost=min(MinCost,e[i][j]+ve[i][k]+ve[k][j]);
for(int i=1;i<=n;i++) //更新k点
for(int j=1;j<=n;j++)
e[i][j]=min(e[i][j],e[i][k]+e[k][j]);
}
if(MinCost==inf) puts("It's impossible.");
else printf("%d\n",MinCost);
}