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

题意很简单:

有多组输入数据,每组的第一行为两个整数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. 关于去哪儿网的UI自动化测试脚本(Python实现)

    UI自动化测试Qunar机票搜索场景访问Qunar机票首页http://flight.qunar.com,选择“单程”,输入出发.到达城市,选择today+7日后的日期,点“搜索”,跳转到机票单程搜索 ...

  2. pl/sql tutorial

    http://plsql-tutorial.com/plsql-procedures.htm What is PL/SQL? PL/SQL stands for Procedural Language ...

  3. POJ 1795

    DNA Laboratory Time Limit: 5000MS   Memory Limit: 30000K Total Submissions: 1425   Accepted: 280 Des ...

  4. POJ 1026 Cipher(置换群)

    题目链接 题意 :由n个数字组成的密钥,每个数字都不相同,都在1-n之间,有一份长度小于等于n的信息,要求将信息放到密钥下边,一一对应,信息不足n的时候补空格,然后将位置重新排列,将此过程重复k次,求 ...

  5. 李洪强iOS开发之OC[013] -类的创建的练习

    // //  main.m //  12 - 类的创建练习 // //  Created by vic fan on 16/7/9. //  Copyright © 2016年 李洪强. All ri ...

  6. *[codility]Peaks

    https://codility.com/demo/take-sample-test/peaks http://blog.csdn.net/caopengcs/article/details/1749 ...

  7. c扩展调用php的函数(调用实现php函数的c函数)

    上一次是写的c扩展调用c的标准函数,但是只能调用头文件中申明的函数,今天来说下c扩展调用实现php函数的c函数,比方说,c扩展要用到php中ip2long这个函数,但是c不可能去php中调用,肯定是去 ...

  8. JAVA使用apache http组件发送POST请求

    在上一篇文章中,使用了JDK中原始的HttpURLConnection向指定URL发送POST请求 可以看到编码量有些大,并且使用了输入输出流 传递的参数还是用“name=XXX”这种硬编的字符串进行 ...

  9. 关于<img>标签与文字垂直居中

    要让左边的图片与后面的文字居中,如下效果 HTML代码: <img class="iconCls" alt="最新客户端" src="${bas ...

  10. Discuz 7.2 /faq.php SQL注入漏洞

    测试方法: 提供程序(方法)可能带有攻击性,仅供安全研究与教学之用,风险自负!   Discuz 7.2 /faq.php SQL注入漏洞   http://www.xxx.com/faq.php?a ...