最短路(代码来源于kuangbin和百度)
最短路
最短路有多种算法,常见的有一下几种:Dijstra、Floyd、Bellman-Ford,其中Dijstra和Bellman-Ford还有优化;Dijstra可以用优先队列(或者堆)优化,Bellman-Ford也可以用队列优化,通常称为spfa。下面分别对这几种算法进行说明。
Dijstra适用于没有负权边的图,Bellman-Ford适用于有负权边的图,但是不能得到有负环的图的最短距离,只能判断有没有负环。Dijstra和Bellman-Ford都是单源最短路,Floyd算法是多源最短路。
一、Dijstra算法
Dijstra算法是不断将新的距离原点最短的点加入已经得到最短距离的集合,然后每加入一个点都更新各个点到源点的距离。这里有一个问题,设已经的到最短距离的点的集合为V,如何保证已经加入V的点已经得到了最短距离而之后源点到V中的点的最短距离不会改变了呢?假设i点已经加入V,而j点后来加入V,因为所有的边权值都是正的,如果存在dis[j]+cost[j][i]<dis[i](dis[i]表示i点到源点的距离,cost[i][j]表示i点到j点的边的权值),那么dis[j]<dis[i],如果dis[j]<dis[i],j点就应该先于i点加入V,与已知条件不符。所以在i点加入V之后,不会存在一个点作为中间点使得源点到i点的距离最小。
Dijstra算法的过程如下:

代码:
/*
* 单源最短路径,Dijkstra算法,邻接矩阵形式,复杂度为O(n^2)
* 求出源beg到所有点的最短路径,传入图的顶点数,和邻接矩阵cost[][]
* 返回各点的最短路径lowcost[], 路径pre[].pre[i]记录beg到i路径上的父结点, pre[beg]=-1
* 可更改路径权类型,但是权值必须为非负
*
*/
const int MAXN=;
#define typec int
const typec INF=0x3f3f3f3f;//防止后面溢出,这个不能太大
bool vis[MAXN];
int pre[MAXN];
void Dijkstra(typec cost[][MAXN],typec lowcost[],int n,int beg)
{
for(int i=;i<n;i++)
{
lowcost[i]=INF;
vis[i]=false;
pre[i]=-;
}
lowcost[beg]=;
for(int j=;j<n;j++)
{
int k=-;
int Min=INF;
for(int i=;i<n;i++)
if(!vis[i]&&lowcost[i]<Min)
{
Min=lowcost[i];
k=i;
}
if(k==-)
break;
vis[k]=true;
for(int i=;i<n;i++)
if(!vis[i]&&lowcost[k]+cost[k][i]<lowcost[i])
{
lowcost[i]=lowcost[k]+cost[k][i];
pre[i]=k;
}
}
}
二、Dijstra+优先队列
将每次选取到达源点最近点的过程用一个优先队列代替,直接出队得到最近点和距离。但要把已经处理过的点涉及到的已经入队的略过不处理。
代码:
/*
* 使用优先队列优化Dijkstra算法
* 复杂度O(ElogE)
* 注意对vector<Edge>E[MAXN]进行初始化后加边
*/
const int INF=0x3f3f3f3f;
const int MAXN=;
struct qnode
{
int v;
int c;
qnode(int _v=,int _c=):v(_v),c(_c){}
bool operator <(const qnode &r)const
{
return c>r.c;
}
};
struct Edge
{
int v,cost;
Edge(int _v=,int _cost=):v(_v),cost(_cost){}
};
vector<Edge>E[MAXN];
bool vis[MAXN];
int dist[MAXN];
void Dijkstra(int n,int start)//点的编号从1开始
{
memset(vis,false,sizeof(vis));
for(int i=;i<=n;i++)
dist[i]=INF;
priority_queue<qnode>que;
while(!que.empty())
que.pop();
dist[start]=;
que.push(qnode(start,));
qnode tmp;
while(!que.empty())
{
tmp=que.top();
que.pop();
int u=tmp.v;
if(vis[u])
continue;
vis[u]=true;
for(int i=;i<E[u].size();i++)
{
int v=E[tmp.v][i].v;
int cost=E[u][i].cost;
if(!vis[v]&&dist[v]>dist[u]+cost)
{
dist[v]=dist[u]+cost;
que.push(qnode(v,dist[v]));
}
}
}
}
void addedge(int u,int v,int w)
{
E[u].push_back(Edge(v,w));
}
三、Bellman-Ford算法
Bellman-Ford算法是对每条边进行松弛,重复|V|次,时间复杂度是O(V*E),伪代码如下:
for(i = 0; i < |V|; i++)
for each edge(u, v) ∈ E
RELAX(u, v)
算法简单,但是实际中不被采用,因为存在大量的无效松弛。
代码:
/*
* 单源最短路bellman_ford算法,复杂度O(VE)
* 可以处理负边权图。
* 可以判断是否存在负环回路。返回true,当且仅当图中不包含从源点可达的负权回路
* vector<Edge>E;先E.clear()初始化,然后加入所有边
* 点的编号从1开始(从0开始简单修改就可以了)
*/
const int INF=0x3f3f3f3f;
const int MAXN=;
int dist[MAXN];
struct Edge
{
int u,v;
int cost;
Edge(int _u=,int _v=,int _cost=):u(_u),v(_v),cost(_cost){}
};
vector<Edge>E;
bool bellman_ford(int start,int n)//点的编号从1开始
{
for(int i=;i<=n;i++)dist[i]=INF;
dist[start]=;
for(int i=;i<n;i++)//最多做n-1次
{
bool flag=false;
for(int j=;j<E.size();j++)
{
int u=E[j].u;
int v=E[j].v;
int cost=E[j].cost;
if(dist[v]>dist[u]+cost)
{
dist[v]=dist[u]+cost;
flag=true;
}
}
if(!flag)
return true;//没有负环回路
}
for(int j=;j<E.size();j++)
if(dist[E[j].v]>dist[E[j].u]+E[j].cost)
return false;//有负环回路
return true;//没有负环回路
}
四、Spfa
Spfa是Bellman-Ford算法利用队列的优化,Bellman-Ford算法存在大量的无效松弛,spfa对它进行改进,对于每个点只松弛与这个点相关的边。

代码:
/*
* 单源最短路SPFA
* 时间复杂度 0(kE)
* 这个是队列实现,有时候改成栈实现会更加快,很容易修改
* 这个复杂度是不定的
*/
const int MAXN=;
const int INF=0x3f3f3f3f;
struct Edge
{
int v;
int cost;
Edge(int _v=,int _cost=):v(_v),cost(_cost){}
};
vector<Edge>E[MAXN];
void addedge(int u,int v,int w)
{
E[u].push_back(Edge(v,w));
}
bool vis[MAXN];//在队列标志
int cnt[MAXN];//每个点的入队列次数
int dist[MAXN];
bool SPFA(int start,int n)
{
memset(vis,false,sizeof(vis));
for(int i=;i<=n;i++)
dist[i]=INF;
vis[start]=true;
dist[start]=;
queue<int>que;
while(!que.empty())
que.pop();
que.push(start);
memset(cnt,,sizeof(cnt));
cnt[start]=;
while(!que.empty())
{
int u=que.front();
que.pop();
vis[u]=false;
for(int i=;i<E[u].size();i++)
{
int v=E[u][i].v;
if(dist[v]>dist[u]+E[u][i].cost)
{
dist[v]=dist[u]+E[u][i].cost;
if(!vis[v])
{
vis[v]=true;
que.push(v);
if(++cnt[v]>n) //cnt[i]为入队列次数,用来判定是否存在负环回路
return false;
}
}
}
}
return true;
}
五、Floyd算法
Floyd算法是多源最短路,算法是将每对顶点(i,j)之间的所有其他点都进行松弛。
其状态转移方程如下: map[i,j]=min{map[i,k]+map[k,j],map[i,j]};
代码:
#include<stdio.h>
#include<stdlib.h>
#define max 1000000000 int d[][],path[][];
int main()
{
int i,j,k,m,n;
int x,y,z;
scanf("%d%d",&n,&m); for(i=;i<=n;i++)
for(j=;j<=n;j++){
d[i][j]=max;
path[i][j]=j;
} for(i=;i<=m;i++)
{
scanf("%d%d%d",&x,&y,&z);
d[x][y]=z;
d[y][x]=z;
} for(k=;k<=n;k++)
for(i=;i<=n;i++)
for(j=;j<=n;j++)
{
if(d[i][k]+d[k][j]<d[i][j]){
d[i][j]=d[i][k]+d[k][j];
path[i][j]=path[i][k];
}
} for(i=;i<=n;i++)
for(j=;j<=i;j++)
if (i!=j) printf("%d->%d:%d\n",i,j,d[i][j]); int f,en;
scanf("%d%d",&f,&en);
while (f!=en){
printf("%d->",f);
f=path[f][en];
}
printf("%d\n",en); return ;
}
最短路(代码来源于kuangbin和百度)的更多相关文章
- Qt的QWebChannel和JS、HTML通信/交互驱动百度地图
Qt的QWebChannel和JS.HTML通信/交互驱动百度地图 0 前言 我一个研究嵌入式的,不知道怎么就迷上了上位机,接了几个项目都是关于Qt,这个项目还是比较经典的,自己没事儿的时候也进行研究 ...
- 图论算法(二)最短路算法:Floyd算法!
最短路算法(一) 最短路算法有三种形态:Floyd算法,Shortset Path Fast Algorithm(SPFA)算法,Dijkstra算法. 我个人打算分三次把这三个算法介绍完. (毕竟写 ...
- 【C#代码实战】群蚁算法理论与实践全攻略——旅行商等路径优化问题的新方法
若干年前读研的时候,学院有一个教授,专门做群蚁算法的,很厉害,偶尔了解了一点点.感觉也是生物智能的一个体现,和遗传算法.神经网络有异曲同工之妙.只不过当时没有实际需求学习,所以没去研究.最近有一个这样 ...
- 百度地图、ECharts整合HT for Web网络拓扑图应用
前一篇谈及到了ECharts整合HT for Web的网络拓扑图应用,后来在ECharts的Demo中看到了有关空气质量的相关报表应用,就想将百度地图.ECharts和HT for Web三者结合起来 ...
- FJNU 1196 汪老司机(DP or 建图+最短路)
1196: 汪老司机 Time Limit: 1000 MS Memory Limit: 257792 KB 64-bit interger IO format: %lld ...
- IOS苹果和百度地图的相关使用
iOS中使用较多的3款地图,google地图.百度地图.苹果自带地图(高德).其中苹果自带地图在中国使用的是高德的数据.苹果在iOS 6之后放弃了使用谷歌地图,而改用自家的地图.在国内使用的较多的就是 ...
- Visual Studio Entity Framework (EF) 生成SQL 代码 性能查询
Visual Studio Entity Framework (EF) 生成SQL 代码 性能查询 SQL 中,有SQL Server Profiler可以用来查询性能以及查看外部调用的SQL ...
- 今天心情好,一起探讨下《送给大家的200兆SVN代码服务器》怎么管理我们的VS代码?
前几天给大家免费送了个200兆SVN代码服务器(今天心情好,给各位免费呈上200兆SVN代码服务器一枚,不谢!),还木有领取的速度戳链接哦! 好几位园友拿到SVN服务器都对其赞不绝口,我也用这个服务器 ...
- ECharts+百度地图网络拓扑应用
前一篇谈及到了ECharts整合HT for Web的网络拓扑图应用,后来在ECharts的Demo中看到了有关空气质量的相关报表应用,就想将百度地图.ECharts和HT for Web三者结合起来 ...
随机推荐
- C#单例模式的多种写法
它的主要特点不是根据客户程序调用生成一个新的实例,而是控制某个类型的实例数量-唯一一个.(<设计模式-基于C#的工程化实现及扩展>,王翔).也就是说,单例模式就是保证在整个应用程序的生命周 ...
- iOS监听tableView组头切换事件
- (void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view forSection:(NSIntege ...
- StringBuffer与StringBuilder的简单理解
联系:两者都适用于字符串的操作,都可以随便对字符串的内容进行变更操作,都继承至AbstractStringBuilder. 区别:StringBuffer是线程安全的,方法都加了synchronize ...
- memcache入门笔记
向memcached保存数据时可以指定期限(秒).不指定期限时,memcached按照LRU算法保存数据. 这三个方法的区别如下: 选项 说明 add 仅当存储空间中不存在键相同的数据时才保存 rep ...
- Delphi容器类之---TList、TStringList、TObjectList,以及一个例程的代码分析
转载自:http://blog.csdn.net/jqandjq/article/details/5429137 看了这里标题,大家可能以为我会谈TListBox控件,那就错了.我要谈的是Delphi ...
- Jenkins+Maven+SVN快速搭建持续集成环境
http://www.cnblogs.com/sunzhenchao/archive/2013/01/30/2883289.htmlhttp://blog.csdn.net/pein_zero/art ...
- LD算法获取字符串相似度
一个如何识别相似语句的问题,于是上网找了找,一个叫Levenshtein Distance的算法比较简单,就写了段代码实现了一下,效果还不错. 这个算法是一个俄国人Lvenshtein提出的,用于计算 ...
- 【转】C# 控件的自定义拖动、改变大小方法
在用VS的窗体设计器时,我们可以发现控件都是可以拖动的,并且还可以调整大小.怎么在自己的程序中可以使用上述功能呢? 下面的方法值得借鉴! using System; using System.Wind ...
- linux下tar安装mysql
>>>>>>>>>>>>>>>>>>>> 到官网下载 mysql-5.6.12- ...
- 如何动态在spring mvc中增加bean
阅读对象 搭框架人员,或者其他感兴趣的开发人员 背景 一般来说在业务代码中,加上 @Component, @Service,@Repository, @Controller等注解就可以实现将bean注 ...