Floyd算法&Prim算法

简介: 一、Floyd算法解决全源最短路径问题——求任意两点u、v之间的最短路径长度,dis[i][j]表示从顶点i到顶点j的最短距离,伪代码如下:枚举顶点k

一、Floyd算法

解决全源最短路径问题——求任意两点u、v之间的最短路径长度,dis[i][j]表示从顶点i到顶点j的最短距离,伪代码如下:

枚举顶点k
  以顶点k作为中介点,枚举所有顶点对i和j
    如果dis[i][k]+dis[k][j]<dis[i][j]成立
      赋值dis[i][j]=dis[i][k]+dis[k][j]

小栗子

#include<cstdio>
#include<algorithm>
using namespace std;
const int INF=1000000000;
const int MAXV=200;
int n,m;//n为顶点数,m为边数
int dis[MAXV][MAXV];//dis[i][j]为顶点i和j的最短距离
void Floyd(){
  for(int k=0;k<n;k++){
    for(int i=0;i<n;i++){
      for(int j=0;j<n;j++){
        if(dis[i][k]!=INF&&dis[k][j]!=INF&&dis[i][k]+dis[k][j]<dis[i][j]){
          dis[i][j]=dis[i][k]+dis[k][j];//找到更短的路径
        }
      }
    }
  }
}
int main(){
  int u,v,w;
  fill(dis[0],dis[0]+MAXV*MAXV,INF);//dis数组赋初值
  scanf("%d%d",&n,&m);//顶点数n,边数m
  for(int i=0;i<n;i++){
    dis[i][i]=0;//顶点i到顶点i的距离初始化为0
  }
  for(int i=0;i<m;i++){
    scanf("%d%d%d",&u,&v,&w);
    dis[u][v]=w;//u点指向v点的边权为w
  }
  Floyd();
  for(int i=0;i<n;i++){//输出dis数组
    for(int j=0;j<n;j++){
      printf("%d ",dis[i][j]);
    }
    printf("\n");
  }
  //return 0;
  system("pause");
}

注意:

不能将最外层的k循环放到内层(即产生i->j->k的三重循环),否则如果当较后访问的dis[u][v]能优化后,之前访问的dis[i][j]会因为已经被访问而无法获得进一步优化(这里i、j先于u、v进行访问)。

二、Prim算法

(1)模板

求最小生成树,

基本思想

——对图设置集合S(存放已经被访问的顶点),然后执行n次下面的2个步骤(n个顶点):

1)每次从集合V-S中选择与集合S最近的一个顶点(记作u),访问u并将其加入集合S,同时把这条离集合S最近的边加入最小生成树中。

2)令u点作为集合S与集合V-S连接的接口,优化从u能到达的未访问顶点v与集合S的最短距离。

解决最小生成树问题。

//G为图,一般设为全局变量,数组d为顶点与集合S的最短距离
Prim(G,d[]){
  初始化;
  for(循环n次){
    u=使d[u]最小的还未被访问的顶点的标号
    记u已被访问;
    for(从u出发能到达的所有顶点v){
      if(v未被访问&&以u为中介点使得v与集合S的最短距离d[v]更优){
        将G[u][v]赋值给v与集合S的最短距离d[v]
      }
    }
  }

PrimDijkstra算法思路类似,只有d[]含义不同——前者d[]指顶点Vi与集合S的最短距离, 后者的d[]指起点s到达顶点Vi的最短距离;区别在于最短距离是顶点Vi针对“起点s”还是“集合S”。

具体实现(邻接矩阵版本)

const int MAXV=1000;//最大顶点数
const int INF=1000000000;//设INF为一个很大的数
int n,G[MAXV][MAXV];//n为顶点数,MAXV为最大顶点数
int d[MAXC];//顶点与集合S的最短距离
bool vis[MAXV]={false};//访问数组
int prim(){//默认0号为初始点,函数返回最小生成树的边权之和
  fill(d,d+MAXV,INF);
  d[0]=0;//只有0号顶点到集合S的距离为0,其余为INF
  int ans=0;//存放最小生成树的边权之和
  for(int i=0;i<n;i++){
    int u=-1,MIN=INF;//u使d[u]最小,MIN存放该最小的d[u]
    for(int j=0;j<n;j++){//找到未访问的顶点中d[]最小的
      if(vis[j]==false&&d[j]<MIN){
        u=j;
        MIN=d[j];
      }
    }
    //找不到小于INF的d[u],则剩下的顶点和集合S不连通
    if(u==-1) 
      return -1;
    vis[u]=true;
    ans+=d[u];//将与集合S距离最小的边加入最小生成树
    for(int v=0;v<n;v++){
      //v未访问&&u能到达v&&以u为中介点可以使v离集合S更近
      if(vis[v]==false&&G[u][v]!=INF&&G[u][v]<d[v]){
        d[v]=G[u][v];
      }
    }
  }
  return ans;//返回最小生成树的边权之和
}

2)小试牛刀

题目:

一个无向图,顶点为N个,其中M条边已给定,现在要从K条备选边中选出若干条,使得整个图连通,且选出的边权值和最小。

4 4

1 2 2

1 4 1

2 3 3

3 4 4

第一行的两个数据分别为N顶点个数和边M的个数;下面的M行为每条边的数据,

起始点和终点,还有每条边的权值。本数据使整个图连通的最小权值之和为6.

相关文章
|
4月前
|
算法
最短路之Floyd算法
最短路之Floyd算法
59 1
|
4月前
|
算法
Floyd 最短路径【学习算法】
Floyd 最短路径【学习算法】
50 0
|
10月前
|
算法
Floyd算法的应用
Floyd算法的应用
54 0
|
11月前
|
算法
最小生成树算法:Prim算法
在图论中,最小生成树(Minimum Spanning Tree,简称MST)是一种常用的算法问题。最小生成树是指在一个加权连通图中选取边的子集,使得所有顶点都被覆盖,并且边的总权值最小。
211 0
|
28天前
|
机器学习/深度学习 算法 Java
算法设计(动态规划应用实验报告)实现基于贪婪技术思想的Prim算法、Dijkstra算法
这篇文章介绍了基于贪婪技术思想的Prim算法和Dijkstra算法,包括它们的伪代码描述、Java源代码实现、时间效率分析,并展示了算法的测试用例结果,使读者对贪婪技术及其应用有了更深入的理解。
算法设计(动态规划应用实验报告)实现基于贪婪技术思想的Prim算法、Dijkstra算法
|
28天前
|
算法 Java 测试技术
算法设计(动态规划实验报告) 基于动态规划的背包问题、Warshall算法和Floyd算法
这篇文章介绍了基于动态规划法的三种算法:解决背包问题的递归和自底向上实现、Warshall算法和Floyd算法,并提供了它们的伪代码、Java源代码实现以及时间效率分析。
算法设计(动态规划实验报告) 基于动态规划的背包问题、Warshall算法和Floyd算法
|
2月前
|
机器学习/深度学习 人工智能 算法
|
3月前
|
存储 算法 C语言
数据结构学习记录——图-最短路径问题(无权图单源最短路径算法、有权图单源最短路径算法、多源最短路径算法、Dijkstra(迪杰斯特拉)算法、Floyd算法)
数据结构学习记录——图-最短路径问题(无权图单源最短路径算法、有权图单源最短路径算法、多源最短路径算法、Dijkstra(迪杰斯特拉)算法、Floyd算法)
55 1
|
3月前
|
算法 C语言
数据结构与算法——最小生成树问题(什么是最小生成树、Prim算法、Kruskal算法)
数据结构与算法——最小生成树问题(什么是最小生成树、Prim算法、Kruskal算法)
24 0
|
4月前
|
算法
Frogger(Floyd算法)
Frogger(Floyd算法)