NOJ 1137 The Running Man

地址:http://acm.nbut.edu.cn/Problem/view.xhtml?id=1137

本题的题意就是告诉你有t个地点,从A, B, C...到A+t-1为止,然后再告诉你一些道路以及距离,表示连接两地且是单向的。最后让你输出从A点为起点,到其他点的最短路径是多少?如果无法到达则输出No。

那么此题就是一个简单的单源最短路问题。
所谓单源就是只有一个起点。
对于单源最短路,我这里只介绍一下 Dijkstra算法。

在介绍 Dijkstra算法之前,我首先来讲一下一个容器——队列。
C语言包含头文件<queue.h>;C++包含头文件<queue>。
队列的一个思想就是先进先出(后进后出),就好像一群人排队打饭,先进入队伍的肯定要先打到饭然后离开(出队)。
对于该容器的其他操作我就不讲了,这里只讲一些基础的。
首先是定义:queue<int> q;//定义一个队列q
一些函数(操作):
pop();//将最先进入队列的元素删除,例如q.pop();
push();//丢入一个元素到队尾,例如q.push(a), q.push(7);
empty();//判断该队里是否为空,为空返回1,否则返回0;
front();//获取队首元素,例如int a = q.front();
注意点:使用队里前需要先清空:

while (!q.empty())

{

q.pop();

}

对于这些容器,大家也要学会自己去写一个实现,不能只是一味使用。
我们不是大自然的搬运工,农夫山泉才是。

Dijkstra算法
对于题目所给的图,我们先将所有的边都去掉,也就是将图转换为无边状态。
那么我们建立一个一维数组s_dis[ ](即shortest distance)来保存从起点到各个点的最短路径。那么初始化该数组,起点为0,其余点都为+oo(正无穷大),很好理解,从起点到起点那距离肯定是0,正无穷大就表示从起点到不了该点,因为还没连接边呢,当然到不了。
然后将输入的点与点的关系存在数组map[ ][ ]中,map[i][j]表示从点i到点j的距离,-1表示不可达。

那么,我们首先将起点s加入队列中,然后我们开始循环(循环的结束条件是队列为空)。
首先我们获取队首元素int now = q.front();表示我当前在now这个点,那么now能到哪些点呢?这就要来看map[now][j]了,如果map[now][j]不为-1,就表示now能到达j,那么遍历j。

那么怎么来判断我到j这个点是否比以前到这个点的距离要短还是长呢?别着急,往下看。
还记得s_dis[ ]数组吗?他是用来储存从起点到其他所有点的最短距离的(本题起点为'A',我将其转化为了0),那么s_dis[5]就表示从0到5的最短距离。s_dis[now]就表示从0到now的最短距离。

当我们遍历到map[now][j]不是-1时,那么就表示我可以从now走到j。假如我们要走到j这个点,那么起点到j的当前最短距离是多少呢?那就是从起点到now的最短距离加上从now到j的距离,也就是s_dis[now]+map[now][j];这只是当前的哦,我们还需要与历史(曾经)的起点到j这个点的最短距离比较一下。
曾经的起点到j的最短距离存在哪呢?对了,就是s_dis[j]里,如果当前最短距离比之前最短距离长(s_dis[now]+map[now][j] >= s_dis[j]),说明当前不是最优解;如果当前最短距离比之前最短距离短(s_dis[now]+map[now][j] < s_dis[j]),说明当前最短距离在目前来看是最优解(以后还不知道),那么我们就应该把点j加入队列(为什么加入?因为该点的影响也许会带来其他点的影响),直到我遍历完now所连接的所有点时,那么就该遍历队列里的下一个点了(pop一下,然后又是now = q.front();进行下一个点的遍历)。直到队列为空后,我们结束遍历,那么此时的s_dis数组里所存的数值就是最优解了(有疑问的可以留言本日志~)。
那么本题也可以解决了~

以上如有错误,欢迎指出,谢谢~
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值