最短路径问题是图论中很重要的问题。

解决最短路径几个经典的算法

1、Dijkstra算法

单源最短路径(贪心),还有用 priority_queue 进行优化的 Dijkstra 算法。

2、bellman-ford算法

例题:【ACM】POJ 3259 Wormholes

允许负权边的单源最短路径算法

优点:可以发现负圈。缺点,时间复杂度比Dijkstra算法高。

算法流程:

(1)初始化:将除源点外的所有顶点的最短距离估计值d[v]趋于正无穷,d[start]=0

(2)迭代求解:反复对边集E中的每条边进行松弛操作,使得顶点V中的每个顶点v的最短距离估计值逐步逼近其最短距离(运行|v|-1次)

(3)检验负权回路:判断边集E中的每一条边的两个顶点是否收敛。如果存在未收敛的顶点,则算法返回false,表明问题无解,否则算法返回true,并从源点可达的顶点v的最短距离保存在d[v]中。

Bellman-Ford(G,w,s) :boolean   //图G ,边集 函数 w ,s为源点1        for each vertex v ∈ V(G) do        //初始化 1阶段2            d[v] ←+∞3        d[s] ←0;                             //1阶段结束4        for i=1 to |v|-1 do               //2阶段开始,双重循环。5           for each edge(u,v) ∈E(G) do //边集数组要用到,穷举每条边。6              If d[v]> d[u]+ w(u,v) then      //松弛判断7                 d[v]=d[u]+w(u,v)               //松弛操作   2阶段结束8        for each edge(u,v) ∈E(G) do9            If d[v]> d[u]+ w(u,v) then10            Exit false11    Exit true

3、SPFA

是bellman-ford + 队列优化,其实和bfs关系更密

4、floyd算法

多元最短路算法,是一个经典的动态规划算法

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2544

题目大意是:已知顶点数n,边数及权值,求第1个点到第n个点的最短路的长度

有很多种解法

1、Dijkstra

推荐博客:【算法】【ACM】深入理解Dijkstra算法(单源最短路径算法)

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
using namespace std;
const int INF = 9999999;
int map[105][105];
int d[105];
bool vis[105];
int N,M;void dijkstra()
{int i,j,min,pos;for(i=1;i<N;i++){min = INF;for(j=1;j<=N;j++){if(!vis[j] && d[j]<min){min = d[j];pos = j;}}if(min == INF)return ;vis[pos] = true;for(j=1;j<=N;j++){if(!vis[j] && (min+map[pos][j]<d[j])){d[j] = map[pos][j] + min;}}}
}int main()
{int i,j,a,b,t;while(scanf("%d%d",&N,&M)!=EOF){if(N==0 && M==0)return 0;for(i=0;i<=N;i++){for(j=0;j<=N;j++){if(i==j) map[i][j] = 0;else map[i][j] = INF;}}for(i=0;i<M;i++){cin >> a >> b >> t;if(t < map[a][b]){map[a][b] = t;map[b][a] = t;}}memset(vis,false,sizeof(vis));for(i=1;i<=N;i++)d[i] = map[1][i];vis[1] =true;dijkstra();cout << d[N] << endl; }return 0;
}

2、Floyd 算法

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int maxn = 9999999;
int map[105][105];int main ()
{int n,m;int a,b,c;int i,j,k;while (scanf("%d%d",&n,&m)!=EOF){if(n==0 && m==0)return 0;for(i=1;i<=n;i++){for(j=1;j<=n;j++){if(i==j)  map[i][j] = 0;else map[i][j] = maxn;}}for(i=1;i<=m;i++){cin >> a >> b >> c;if(map[a][b] > c){map[a][b] = map[b][a] = c;}}for(k=1;k<=n;k++){for(i=1;i<=n;i++){for(j=1;j<=n;j++){map[i][j] = min(map[i][j],map[i][k]+map[k][j]);}}}cout << map[1][n] << endl;}return 0;
}

3、Dijkstra + 优先队列 (邻接矩阵表示)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <queue>
#include <vector>
#include <functional>
using namespace std;typedef pair<int,int> p;
const int maxn = 9999999;
int N,M;
int d[105];
bool vis[105];
int map[105][105];void dijkstra()
{int i;memset(vis,false,sizeof(vis));memset(d,maxn,sizeof(d));d[1] = 0;priority_queue<p,vector<p>,greater<p> > q;q.push(make_pair(d[1],1));while(q.empty()!=1){p p1=q.top();q.pop();int pos = p1.second;if(vis[pos])continue;vis[pos] = true;for(i=2;i<=N;i++){if(!vis[i] && d[i]>map[pos][i]+d[pos]){d[i] = map[pos][i]+d[pos];q.push(make_pair(d[i],i));}}}
}int main ()
{int i,j;while(scanf("%d%d",&N,&M)!=EOF){if(N==0 && M==0)return 0;for(i=0;i<=N;i++){for(j=0;j<=N;j++){if(i==j)    map[i][j] = 0;else    map[i][j] = maxn;}}int a,b,c;for(i=0;i<M;i++){cin >> a >> b >> c;if(map[a][b] > c){map[a][b] = c;map[b][a] = c;}}dijkstra();cout << d[N] << endl;}return 0;
}

4、Dijkstra + 优先队列 + vector(邻接表表示)

#include <iostream>
#include <vector>
#include <queue>
#include <string>
#include <cstring>
#include <cstdio>
#include <functional>
using namespace std;
typedef pair<int,int> p;//first是最短距离,second是顶点编号
const int maxn = 9999999;struct edge
{int to;//邻接的点int cost;//以及到该点的权值
};vector<edge> eg[105];//邻接表
bool vis[105];//表示是否已经使用过
int d[105];//最短距离
int n,m;//顶点数和边数void dijkstra()
{//priority_queue,优先队列按first由小到大,默认的是从大到小priority_queue<p,vector<p>,greater<p>> q;//初始化memset(d,maxn,sizeof(d));memset(vis,false,sizeof(vis));d[1] = 0;q.push(p(d[1],1));while(q.empty()!=1){p p1 = q.top();q.pop();int pos = p1.second;if(vis[pos])continue;vis[pos] = true;for(int i=0;i<eg[pos].size();i++){edge x = eg[pos][i];if(d[x.to] > d[pos] + x.cost){//起点到x的距离与 选中的这个pos点+pos到x的距离和 作比较d[x.to] = d[pos] + x.cost;q.push(p(d[x.to],x.to));}}}
}int main ()
{while(scanf("%d%d",&n,&m)!=EOF){int i;if(n==0 && m==0)return 0;for(i=1;i<=n;i++)eg[i].clear();int a,b,c;for(i=1;i<=m;i++){cin >> a >> b >> c;edge g1,g2;//无向图的缘故g1.to = b;g1.cost = c;g2.to = a;g2.cost = c;eg[a].push_back(g1);eg[b].push_back(g2);}dijkstra();cout <<d[n] << endl;}return 0;
}

5、bellman_ford(邻接矩阵)

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;const int maxn = 9999999;
int d[105];
int map[105][105];
int n,m;void bellman_ford()
{memset(d,maxn,sizeof(d));d[1] = 0;int flag = 1;int k,i,j;for(k=0;k<n-1 && flag;k++){flag = 0;for(i=1;i<=n;i++){for(j=1;j<=n;j++){if( map[i][j] && d[i]!=maxn && (d[j]>map[i][j]+d[i]) ){d[j] = map[i][j]+d[i];flag = 1;}}}if(flag == 0)return ;}
}int main()
{int i,j;int a,b,c;while(scanf("%d%d",&n,&m)!=EOF){if(n==0 && m==0)return 0;for(i=0;i<=n;i++){for(j=0;j<=n;j++){if(i==j) map[i][j] = 0;else map[i][j] = maxn;}}for(i=1;i<=m;i++){cin >> a >> b >> c;if(map[a][b] > c){map[a][b] = c;map[b][a] = c;}}bellman_ford();cout << d[n] << endl;}return 0;
}

用边表示

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;const int maxn = 9999999;typedef struct Edge
{int u,v;int weight;
}Edge;
Edge edge[10000+10];
int d[105];
int n,m;void bellman_ford()
{int flag = 1,i,j;for(i=1;i<=n-1 && flag;i++){flag = 0;//因为是无向图,所以是双向的for(j=1;j<=m;j++){if(d[edge[j].v]>d[edge[j].u]+edge[j].weight){d[edge[j].v]=d[edge[j].u]+edge[j].weight;flag = 1;}if(d[edge[j].u]>d[edge[j].v]+edge[j].weight){d[edge[j].u]=d[edge[j].v]+edge[j].weight;flag = 1;}}if(!flag)return ;}
}int main()
{while(scanf("%d%d",&n,&m)!=EOF){if(n==0 && m==0)return 0;memset(d,maxn,sizeof(d));d[1] = 0;for(int i=1;i<=m;i++){cin >> edge[i].u >> edge[i].v >> edge[i].weight;//注意这里设置初始情况if(edge[i].u==1){d[edge[i].v] = edge[i].weight;}}bellman_ford();cout << d[n] << endl;}return 0;
}

6、SPFA(邻接矩阵)因为这个题目不存在负权边,所以就没有记录每个点的入队次数

#include <iostream>
#include <queue>
#include <vector>
#include <cstdio>
#include <cstring>
using namespace std;const int maxn = 9999999;
int n,m;
int map[105][105];
int d[105];
int vis[105];void SPFA()
{memset(vis,false,sizeof(vis));memset(d,maxn,sizeof(d));queue<int> Q;Q.push(1);d[1] = 0;vis[1] = true;int v;while(Q.empty()!=1){int u = Q.front();Q.pop();vis[u] = false;for(v=1;v<=n;v++){if(map[u][v]!=maxn){if(d[u]+map[u][v]<d[v]){d[v] = map[u][v]+d[u];if(!vis[v]){Q.push(v);vis[v] = true;}}}}}
}int main ()
{int i,j;while(scanf("%d%d",&n,&m)!=EOF){if(n==0 && m==0)return 0;for(i=0;i<=n;i++){for(j=0;j<=n;j++){if(i==j)   map[i][j] = 0;else map[i][j] = maxn;}}int a,b,c;for(i=1;i<=m;i++){cin >> a >> b >> c;if(map[a][b]>c){map[a][b] = c;map[b][a] = c;}}SPFA();cout << d[n] << endl;}return 0;
}

用边来表示

#include <iostream>
#include <queue>
#include <vector>
#include <cstdio>
#include <cstring>
using namespace std;struct Edge
{int s,e,w;Edge(){s = -1;e = -1;w = -1;}
};const int maxn = 9999999;
Edge edge[10000+10];
int n,m;
int d[105];
int vis[105];
int all_e;void SPFA()
{memset(vis,0,sizeof(vis));memset(d,maxn,sizeof(d));d[1] = 0;vis[1] = true;queue<int> Q;Q.push(1);int v;while(Q.empty()!=1){int u = Q.front();Q.pop();vis[u] = false;for(v=0;v<all_e;v++){if(d[edge[v].e]>d[edge[v].s]+edge[v].w){d[edge[v].e]=d[edge[v].s]+edge[v].w;if(!vis[edge[v].e]){Q.push(edge[v].e);vis[edge[v].e] = true;}}}}
}int main ()
{int i;while(scanf("%d%d",&n,&m)!=EOF){if(n==0 && m==0)return 0;all_e = 0;int a,b,c;for(i=0;i<m;i++){cin >> a >> b >> c;edge[all_e].s = a;edge[all_e].e = b;edge[all_e++].w = c;edge[all_e].s = b;edge[all_e].e = a;edge[all_e++].w = c;}SPFA();cout << d[n] << endl;}return 0;
}

【HDU/算法】最短路问题 杭电OJ 2544 (Dijkstra,Dijkstra+priority_queue,Floyd,Bellman_ford,SPFA)相关推荐

  1. 田忌赛马贪心算法_杭电oj 1052田忌赛马问题

    问题描述 这是中国历史上的一个著名故事. "那是大约2300年前.田吉将军是齐国的一位高级官员.他喜欢与国王和其他人打赛马." "田和国王都拥有三匹不同级别的赛马,分别是 ...

  2. 杭电OJ第11页2075~2079算法题(C语言)

    目录 2075.A|B? 2076.夹角有多大 2077.汉诺塔IV 2078.复习时间 2079.选课时间 2075.A|B? Problem Description 正整数A是否能被正整数B整除, ...

  3. 杭电OJ第11页2035~2039算法题(C语言)

    目录 2035.人见人爱A^B 2036.改革春风吹满地 2037.今年暑假不AC 2038.Message 2039.三角形 2035.人见人爱A^B Problem Description 求A^ ...

  4. 杭电OJ第11页2085~2089算法题(C语言)

    目录 2085.核反应堆 2086.A1 = ? 2087.剪花布条 2088.Box of Bricks 2089.不要62 2085.核反应堆 Problem Description 某核反应堆有 ...

  5. 杭电OJ第11页2065~2069算法题(C语言)

    目录 2065."红色病毒"问题 2066.一个人的旅行 2067.小兔的棋盘 2068.RPG的错排 2069.Coin Change 2065."红色病毒" ...

  6. 杭电OJ分类题目(4)-Graph

    原题出处:HDOJ Problem Index by Type,http://acm.hdu.edu.cn/typeclass.php 杭电OJ分类题目(4) HDU Graph Theory - U ...

  7. 用python爬取杭电oj的数据

    暑假集训主要是在杭电oj上面刷题,白天与算法作斗争,晚上望干点自己喜欢的事情! 首先,确定要爬取哪些数据: 如上图所示,题目ID,名称,accepted,submissions,都很有用. 查看源代码 ...

  8. 杭电OJ(HDOJ)入门题目列表

    杭电OJ链接: http://acm.hdu.edu.cn/ 注册与使用指南: https://blog.csdn.net/qq_38769551/article/details/101510000 ...

  9. 杭电OJ,已重新开放!HDOJ

    前几天我们介绍了网络上有很多可以练习上机考试刷题的网站,叫做OJ(Online Judge).还提到了一些学校已经公布了复试上机的说明,可以提前练习. 已经有211大学发布计算机专业,研究生复试上机考 ...

最新文章

  1. Chrome 正在测试标签页的预览功能
  2. Apache Maven ToolChains的使用
  3. Linux 系统上出现^H
  4. 【Modern OpenGL】Shader
  5. cmd fsutil 命令 - 创建指定大小文件命令
  6. 到目前为止,Linux下最完整的Samba服务器配置攻略
  7. 纠结的rename命令
  8. 系统管理:传统UNIX文件系统
  9. 两台电脑之间使用ntp做时间同步的总结
  10. 如何获取多屏幕显示器工作区域
  11. 计算机不能连接网络适配器,网络适配器显示未连接的解决方法图文教程
  12. Python爬网易云音乐的那些事
  13. Android 之 APP上架应用宝平台
  14. cocos creator麻将教程系列(九)—— 幼麟棋牌代码讲解
  15. 《算法竞赛入门经典》Chap3
  16. 像素是什么意思,像素与分辨率的区别
  17. socket编程---send函数recv函数详解
  18. 拓嘉启远:拼多多虚拟产品相关分享
  19. 从苏宁电器到卡巴斯基(第二部)第03篇:我在卡巴的日子 III
  20. C# For Q Series Ethernet Communication Library,C#与三菱Q系列PLC以太网通讯库

热门文章

  1. 2021年还适合参加软件测试培训吗
  2. 学习java三个技巧要知道!
  3. 2021年UI设计培训机构哪个好
  4. intellij idea 必知的debug功能
  5. 物联网设备僵尸网络趋势分析
  6. 快应用开发常见问题以及解决方案【持续更新】
  7. 42. fastjson处理下划线和驼峰问题的方法和源码分析
  8. 服务器和普通用户电脑的区别
  9. docker的网络架构配置
  10. Python标准库介绍