这是一道标准的模板题,所以拿来作为这一段时间学习最短路的总结题目。

题意很简单:

有多组输入数据,每组的第一行为两个整数n, m。表示共有n个节点,m条边。

接下来有m行,每行三个整数a, b, c。表示从a到b或从b到a长度为c。

求从1到n的最短路。

先说Floyd——

这个算法看上去就是一个三重for循环,然后在循环里不断对选择的两个节点进行松弛(感觉松弛这两个字很高端有没有)。

算法时间复杂度为O(n^3),n为节点数。所以一般可以用来处理规模1000以下的数据(即100数量级的,但是如果常数比较大的话也会超时,一般都是规模100的数据)。

但是,这是我目前掌握的唯一一个可以直接计算多源最短路的算法(即算法执行之后,获得图中任意两点间的最短路)。

代码如下:

 void Floyd()
{
for(int k = ; k <= n; k++) //选择的中间节点
for(int i = ; i <= n; i++) //选择的源节点,即出发点
for(int j = ; j <= n; j++) //选择的目标节点
if(mp[i][j] > mp[i][k] + mp[k][j])
mp[i][j] = mp[i][k]+mp[k][j]; //如果经过中间节点的路径(即i到k到j)小于直接从i到j,则进行更新操作(松弛)
}

这道题用floyd跑了41ms。

接着是Dijkstra——

Dijkstra的时间复杂度笼统的说是O(n^2), 精确一点是O(n^2+m), 如果源点可达,那么是O(n*lg n+m*lg n) => (m*lg n)。n是点数,m是边数。一般来说,规模10^4的数据是可以在1s内完成的。

Dijkstra可以用来求单源最短路,也就是从一个点出发,到其他所有点的最短路。

注意,当边存在负权的时候,Dijkstra就会求出错误答案了。

 void Dijkstra(int s)  //计算从s到其他所有点的最短路
{
for(int i = ; i <= n; i++) dis[i] = mp[s][i]; //维护一个记录最短路的数组
v[s] = ; //从s到s的最短路已获得,标记为1
int minn, k;
for(int i = ; i <= n; i++) //进行n次,可能小于n提前结束(好像是n-1次?)
{
minn = M;
for(int j = ; j <= n; j++) //寻找当前已经确定的最短路
{
if(!v[j] && minn > dis[j])
{
minn = dis[j];
k = j;
}
}
if(minn == M) break; //提前结束(即到所有点的距离都以找到,v[]全部为1),则提前退出 v[k] = ; //当前最短路已找到,标记为1
for(int j = ; j <= n; j++) //在当前最短路的基础上,寻找到其他未找到点的最短路
if(!v[j] && dis[j] > dis[k]+mp[k][j]) dis[j] = dis[k]+mp[k][j];
}
}

这道题用Dijkstra跑了15ms。

接下来是BellManFord算法——

这个算法就是进行连续松弛,时间复杂度为O(n*m)不能打折,所以效率比Dijkstra低。但是,不超过10^4的数据一般还是可以在1s内完成的

这个算法的优点是可以计算存在负权的图的最短路,同时它也是求单源最短路的算法。它还可以判断图中是否存在负环(存在负环时是没有最短路的)。

 bool BellManFord(int s)
{
for(int i = ; i <= n; i++) dis[i] = mp[s][i];
for(int i = ; i < n; i++)
{
for(int j = ; j <= n; j++)
{
for(int k = ; k <= n; k++)
{
if(dis[j] > dis[k]+mp[j][k]) dis[j] = dis[k]+mp[j][k];
}
}
}
for(int j = ; j <= n; j++) //算法的精髓,在求出一般意义的最短路之后,在进行一次判断操作,以确定是否存在负环
{
for(int k = ; k <= n; k++) if(dis[j] > dis[k]+mp[j][k]) return ; //存在负环,返回0
}
return ;
}

这个算法跑了31ms。

最后是Spfa算法——

这个算法是BellManFord算法的延伸,或者说优化。它的时间复杂度不稳定,不同的图可能算出来的不一样。我目前能写的是用队列的,类似于bfs,据说还有用dfs写的……

总之我对这个算法也不是完全掌握,只是能用而已。

如果Dijkstra也超时的话,可以用这个算法碰碰运气,说不定就过了。

对了,这个算法由于是从BellManFord优化而来的,所以也可以判负环,不过我这个没有写。加一个判断节点入队次数的操作就行了,如果某节点入队大于n次,就是有负环。

这个算法还是很好理解的。

 void Spfa(int s)
{
for(int i = ; i <= n; i++) dis[i] = M;
dis[s] = ;
queue<int>que;
que.push(s);
v[s] = ; int p;
while(!que.empty())
{
p = que.front();
que.pop();
v[p] = ;
for(int i = ; i <= n; i++)
{
if(dis[i] > dis[p]+mp[p][i])
{
dis[i] = dis[p]+mp[p][i];
if(v[i] == )
{
que.push(i);
v[i] = ;
}
}
}
} }

同样跑了15ms。

当然,以上的运行时间并不具有代表性,因为不同的图用不同的算法运行时间总存在差异,尤其是spfa,不过,某种程度上还是可以作为参考的。

整体代码:

 #include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std; const int M = ;
const int N = ; int n, m;
int a, b, c;
int mp[N][N];
bool v[N];
int dis[N]; void Init()
{
for(int i = ; i <= n; i++)
{
for(int j =; j < i; j++)
mp[i][j] = mp[j][i] = M;
mp[i][i] = ;
v[i] = ;
}
for(int i = ; i < m; i++)
{
scanf("%d%d%d", &a, &b, &c);
if(mp[a][b] > c) mp[a][b] = mp[b][a] = c;
}
} void Floyd()
{
for(int k = ; k <= n; k++) //选择的中间节点
for(int i = ; i <= n; i++) //选择的源节点,即出发点
for(int j = ; j <= n; j++) //选择的目标节点
if(mp[i][j] > mp[i][k] + mp[k][j])
mp[i][j] = mp[i][k]+mp[k][j]; //如果经过中间节点的路径(即i到k到j)小于直接从i到j,则进行更新操作(松弛)
} void Dijkstra(int s) //计算从s到其他所有点的最短路
{
for(int i = ; i <= n; i++) dis[i] = mp[s][i]; //维护一个记录最短路的数组
v[s] = ; //从s到s的最短路已获得,标记为1
int minn, k;
for(int i = ; i <= n; i++) //进行n次,可能小于n提前结束(好像是n-1次?)
{
minn = M;
for(int j = ; j <= n; j++) //寻找当前已经确定的最短路
{
if(!v[j] && minn > dis[j])
{
minn = dis[j];
k = j;
}
}
if(minn == M) break; //提前结束(即到所有点的距离都以找到,v[]全部为1),则提前退出 v[k] = ; //当前最短路已找到,标记为1
for(int j = ; j <= n; j++) //在当前最短路的基础上,寻找到其他未找到点的最短路
if(!v[j] && dis[j] > dis[k]+mp[k][j]) dis[j] = dis[k]+mp[k][j];
}
} bool BellManFord(int s)
{
for(int i = ; i <= n; i++) dis[i] = mp[s][i];
for(int i = ; i < n; i++)
{
for(int j = ; j <= n; j++)
{
for(int k = ; k <= n; k++)
{
if(dis[j] > dis[k]+mp[j][k]) dis[j] = dis[k]+mp[j][k];
}
}
}
for(int j = ; j <= n; j++) //算法的精髓,在求出一般意义的最短路之后,在进行一次判断操作,以确定是否存在负环
{
for(int k = ; k <= n; k++) if(dis[j] > dis[k]+mp[j][k]) return ; //存在负环,返回0
}
return ;
} void Spfa(int s)
{
for(int i = ; i <= n; i++) dis[i] = M;
dis[s] = ;
queue<int>que;
que.push(s);
v[s] = ; int p;
while(!que.empty())
{
p = que.front();
que.pop();
v[p] = ;
for(int i = ; i <= n; i++)
{
if(dis[i] > dis[p]+mp[p][i])
{
dis[i] = dis[p]+mp[p][i];
if(v[i] == )
{
que.push(i);
v[i] = ;
}
}
}
} } int main()
{
while(~scanf("%d%d", &n, &m) && (n+m))
{
Init();
//Floyd();
//printf("%d\n", mp[1][n]);
//Dijkstra(1);
//if(BellManFord(1))
Spfa();
printf("%d\n", dis[n]);
}
return ;
}

总之这只是一个入门等级的最短路,接下来还有一大波优化等着我们呢,几乎每个最短路算法都有优化,用优先队列,用堆,用双向队列……哦,天哪!

hdu 2544最短路——最短路的初次总结 UESTC 6th Programming Contest Online的更多相关文章

  1. HDU 2544 单源最短路

    题目链接: 传送门 最短路 Time Limit: 1000MS     Memory Limit: 65536K 题目描述 在每年的校赛里,所有进入决赛的同学都会获得一件很漂亮的t-shirt.但是 ...

  2. HDU 2544(简单最短路)

    http://acm.hdu.edu.cn/showproblem.php?pid=2544 /* 使用pair代替结构 */ #include <iostream> #include & ...

  3. hdu 2544 最短路 Dijkstra

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2544 题目分析:比较简单的最短路算法应用.题目告知起点与终点的位置,以及各路口之间路径到达所需的时间, ...

  4. UESTC 30 &&HDU 2544最短路【Floyd求解裸题】

    最短路 Time Limit: 5000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submiss ...

  5. HDU 2544最短路 (迪杰斯特拉算法)

    传送门: http://acm.hdu.edu.cn/showproblem.php?pid=2544 最短路 Time Limit: 5000/1000 MS (Java/Others)    Me ...

  6. 最短路 HDU 2544

    最短路 Time Limit: 5000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submiss ...

  7. HDU 2544 最短路(邻接表+优先队列+dijstra优化模版)

    最短路 Time Limit: 5000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submiss ...

  8. hdu 2544 最短路 (最短路径)

    最短路 Time Limit: 5000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submiss ...

  9. HDU 2544.最短路-最短路(Dijkstra)

    本来不想写,但是脑子不好使,还是写一下备忘_(:з」∠)_ 最短路 Time Limit: 5000/1000 MS (Java/Others)    Memory Limit: 32768/3276 ...

随机推荐

  1. THUSC 2016游记

    又去北京转了一圈,拿到了很不错的协议,非常的开森 day -1 6.2 上午去pku的同学就走了QAQ 然后波哥说下午要考试,考联考题 我一脸无奈的表示我已经提前要到题目而且看了题了 然后波哥就决定给 ...

  2. 天气API整理,返回的数据格式为json对象

    中国天气的API惨遭封杀,不得已更换其他的API使用吧. 这里大部分API来自APP的数据包截取或者反汇编,所以各开发使用者不得用于商业用途,否则后果自负! 1.金山网址导航 来源:http://ww ...

  3. IP地址字符串与BigInteger的转换

    /**  * Copyright (c) 2010, 新浪网支付中心  *      All rights reserved.  *  * Java IP地址字符串与BigInteger的转换,  * ...

  4. java获取当前操作系统的信息

    java获取当前操作系统的信息 JavaOS虚拟机UnixEXT  从网上收集的一些关于java获取操作系统信息的方法,现在总结一下: 1获取本机的IP地址: private static Strin ...

  5. 遍历并remove HashMap中的元素时,遇到ConcurrentModificationException

    遍历并remove HashMap中的元素时,遇到ConcurrentModificationException for (Map.Entry<ImageView, UserConcise> ...

  6. 1、创建一个JPA project(解决“at least one user library must be selected”问题)

    (注:本系列笔记是在学习尚硅谷JPA课程的时候写下的,结合课程内容和自我理解,方便自己以后进行复习) 一.在创建JPA之前看看什么是JPA 1.Java Persistence API:用于对象持久化 ...

  7. Buffer数据结构和new IO的Memory-mapped files

    一.Buffer类 java.nio.Buffer这个类是用来干什么的?有怎样的结构? "Core Java"中是这样定义的“A buffer is array of values ...

  8. IOS自带json解析类解析json

    - (IBAction)test:(id)sender { NSString *result = @"{\"code\":\"S00000\",\&q ...

  9. MapReduce 中的Map后,sort不能对中文的key排序

    今天写了一个用mapreduce求平均分的程序,结果是出来了,可是没有按照“学生名字”进行排序,如果是英文名字的话,结果是排好序的. 代码如下: package com.pro.bq; import ...

  10. android4.4.2内核移植3.4.1

    01◑ 内核源码总目录下Makefile文件修改: 195行: ARCH ?= $(SUBARCH)替换成: ARCH ?= arm 02◑ arch/arm下makefile: ①差7行 # tes ...