欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

最短路径——Floyd算法与Dijkstra算法

程序员文章站 2022-04-05 22:51:05
...

Floyd算法,也被叫做插点法,可以解决多源最短路径的问题,即通过在两个目标点之间插入第三个点作为中转点,从而达到缩短目标点之间距离的目的

(利用《啊哈!算法》一书中的图片更有助于理解

箭头标记的数字为两点之间的距离,我们可以发现通过某个点可以是另外两个点之间的距离减小,且不影响它们之间的连通性

最短路径——Floyd算法与Dijkstra算法

我们用一个二维数组map[I][j]存储上图,i,j任意两点的序号,map[I][j]的值为这两点间的距离
可得到Floyd算法的核心代码(不难理解哟)
for(int k=1;k<=n;k++)
   for(int i=1;i<=n;i++)
     for(int j=1;j<=n;j++)
     {
         if(map[i][j]>map[i][k]+map[k][j])
             map[i][j]>map[i][k]+map[k][j];
     }
(算法虽简单,但时间复杂度为O(N)^3,无时间限制可以使用,否则容易超时)

HDU2066——一个人的旅行(我用Floyd疯狂超时。。,最后对照大佬的算法水过~~)

最短路径——Floyd算法与Dijkstra算法

#include<cstdio>
#include<algorithm>
#define inf 99999999
bool be[1001], en[1001];
int map[1001][1001];
int max_flag;
int floyd()
{
 int MIN = inf;
 for(int k=1;k<=max_flag;++k)
  for(int i=1;i<=max_flag;++i)
   if (map[i][k] != inf)//优化,若这两个点之间无路连接,则不能作为中转路线
   {
    for (int j = 1; j <= max_flag; ++j)
    {
     map[i][j] = map[i][j]<map[i][k]+map[k][j]?map[i][j]: map[i][k] +map[k][j];//更新两点的最小距离
     if (be[i] && en[j]&& MIN > map[i][j])
      MIN = map[i][j];
    }
   }
 return MIN;
}
int main()
{
 int T, S, D, a, b, c, x, y;//x为起点,y为终点
 while (scanf_s("%d%d%d", &T, &S, &D) != EOF)
 {
  for (int i = 1; i <= 1000; ++i)
   for (int j = 1; j <= 1000; ++j)
    map[i][j] = inf;//不知是不是数组太大的原因,用memset会超时,并且inf一大数据就会溢出,往哪位路过的大佬解答
  max_flag = 0;
  for (int i = 1; i <= T; ++i)
  {
   scanf_s("%d%d%d", &a, &b, &c);
   max_flag = max_flag < b ? b : max_flag;
   max_flag = max_flag < a ? a : max_flag;
   //max_flag = max(max(max_flag, a), b);//记录标号最大的一点,确定计算的范围
   map[a][b] = map[b][a] = map[a][b] < c ? map[a][b] : c;
   //map[a][b] = map[b][a] = max(map[a][b], c);
  }
  memset(be, false, sizeof(be));
  memset(en, false , sizeof(en));
  for (int j = 1; j <= S; ++j)
  {
   scanf_s("%d", &x);
   be[x] = true;
  }
  for (int k = 1; k <= D;++k)
  {
   scanf_s("%d", &y);
   en[y] = true;
  }
  printf("%d\n", floyd());
 }
 return 0;
}

Dijkstra算法(单源最短路径O(N)^2),用一个一维数组存储起点到目标点的距离,用二维数组通过中转点对距离进行更新

该题的Dijkstra算法

#include<cstdio>
#include<algorithm>
using namespace std;
const int inf = 0x3fffffff;
int map[1010][1010];
int dis[1010];//dis[i]记录起点到点i的距离
int book[1010];//记录该点是否与起点连接
int st[1010], en[1010];
int n,flag;
void Dijkstra()
{
 int i, j,k, MIN;
 for (i = 1; i <=n; i++)
 {
  MIN = inf;
  for (j = 1; j <= n; j++)//找到与起点最近的一点作为新的起点
  {
   if (book[j] == 0 && dis[j] < MIN)
   {
    MIN = dis[j];
    flag = j;
   }
  }
  book[flag] = 1;
  for (k = 1; k <= n; k++)
  {
   if (dis[k] > dis[flag] + map[flag][k]&&book[k]==0)
    dis[k] = dis[flag] + map[flag][k];
  }
 }
}
int main()
{
 int T, S, D, a, b, c;
 while (scanf("%d%d%d", &T, &S, &D) != EOF)
 {
  for(int i=0;i<1001;i++)
            book[i]=0;
  book[0] = 1;
  n = 0;
  for (int i = 0; i < 1001; i++)
  {
   for (int j = 0; j < 1001; j++)
    map[i][j] = inf;
   map[i][i] = 0;
  }
  while (T--)
  {
   scanf("%d%d%d", &a, &b, &c);
   n = max(max(n, a), b);
   if (c < map[a][b])
    map[a][b] = map[b][a] = c;
  }
  int MIN = inf;
  for (int i = 0; i < S; i++)
  {
   scanf("%d", &st[i]);
   map[0][st[i]] = map[st[i]][0] = 0;//家到这些城市的距离初始化为0
  }
  for(int i=0;i<=n;i++)
     dis[i]=map[0][i];
  for(int i=0;i<n;i++)
     scanf("%d",&en[i]);
  Dijkstra();
  for(int i=0;i<n;i++)
     MIN=min(MIN,dis[en[i]];
  printf("%d",MIN);
 }
 return 0;
}