例1:下面是城市的地图,注意是单向图,求城市1到城市5的最短距离。(引用的是上次总结的图论(一)中1)的例2)(来源于qibofang)
弗洛伊德算法原理:依次以每一点为中心点,带入图中的所有边中,通过比较ege[i][j]>ege[i][k]+ege[k][j]的大小来得到两点间最小的边,依次以每一点循环后比较后即可得到所有点到点之间的最短路径。
下面是弗洛伊德算法解题代码:
#include<bits/stdc++.h>
using namespace std;
#define inf 999999999
#define LL long long
long long yue[1000]={0};
int ege[10][10];
//深度搜索dfs,需要定义一个最短路径,一个访问标记点
int n=5,m=8,miniPath=inf,mark[8]={0};
void dfs(int cur,int dst){
//出口条件,满足寻找到最后一个点的时候
if(cur==n){
//for(int i=1;i<=5;i++){
// cout<<mark[i];
//}
//cout<<dst<<endl;
if(miniPath>dst)
miniPath=dst;
else
return;
}
//如果是大于的话就直接返回,无效路
if(dst>miniPath)
return;
else
for(int i=1;i<=n;i++){
//如果此路可走下去,则继续往下面走
if(ege[cur][i]!=inf&&mark[i]==0&&ege[cur][i]!=0){
mark[i]=1;
dfs(i,dst+ege[cur][i]);
//结束后置为未访问
mark[i]=0;
}
}
}
void print(){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++)
printf("%d ",ege[i][j]);
cout<<endl;
}
}
//以一个中间点为过度,来判断两点间的距离是否为最小,循环遍历每一个点
void floyd(){
for(int k=1;k<=n;k++){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(ege[i][k]!=inf&&ege[k][j]!=inf&&ege[i][j]>ege[i][k]+ege[k][j])
ege[i][j]=ege[i][k]+ege[k][j];
}
}
}
}
int main()
{
for(int i=1;i<=5;i++){
for(int j=1;j<=5;j++){
ege[i][j]=inf;
}
ege[i][i]=0;
}
ege[1][2]=2;ege[1][5]=10;
ege[2][3]=3;ege[2][5]=7;
ege[3][1]=4;ege[3][4]=4;
ege[4][5]=5;
ege[5][3]=3;
mark[1]=1;
print();
floyd();
print();
cout<<ege[1][n];
}
这里涉及到了求最小公约数的算法思路,使用到了欧几里得算法,如果两个数不断相模后所得的数,最终到0,则这个数为最小公约数。
同理,如果想求最小公倍数,只需先求出两个数的最小数,然后两数相乘再除以公约数既为最小公倍数。
下面是使用迪杰斯特拉算法解决蓝桥杯算法题中的路径问题代码。
代码:
#include<bits/stdc++.h>
using namespace std;
#define inf -1
#define LL long long
int line[2050][2050];
int go[2050]= {0};
long long dst[2050]= {0};
int lowa(int la,int lb)
{
if(lb==0)
return la;
else
{
lowa(lb,la%lb);
}
}
void print()
{
for(int i=1; i<=50; i++)
{
cout<<dst[i]<<" ";
}
cout<<endl;
}
int high(int m,int n)
{
return m*n/lowa(m,n);
}
int main()
{
for(int i=1; i<=2021; i++)
{
for(int j=1; j<=2021; j++)
{
if(abs(i-j)<=21)
{
line[i][j]=high(i,j);
line[j][i]=line[i][j];
}
else
{
line[i][j]=inf;
line[j][i]=inf;
}
}
}
//初始化dst列表为第一行
for(int i=1; i<=2021; i++)
{
dst[i]=line[1][i];
}
int cur=1;
go[cur]=1;
for(int k=1; k<=2021; k++)
{
long long min=0;
//找一行内的最小值
for(int i=1; i<=2021; i++)
{
if(go[i]==0&&dst[i]!=inf&&(dst[i]<min||min==0))
{
min = dst[i];
cur = i;
}
}
go[cur]=1;
//更新dst数组
for(int i=1; i<=2021; i++)
{
if(go[i]==0&&line[cur][i]!=inf&&(dst[i]>(dst[cur]+line[cur][i])||dst[i]==inf))
dst[i] = dst[cur]+line[cur][i];
}
cout<<cur<<endl;
//print();
}
print();
cout<<dst[2021];
}