最短路?那是什么 °▽°
来源:互联网 发布:帝王蟹上岸要杀死知乎 编辑:程序博客网 时间:2024/04/27 23:40
我们要走最短路,因为最短路可以坐在最短时间内使价值最大化。在noip上,有最短路算法,但没有最短路,oier的一切,都是要自己一点一点切题,水题,一点一点得来的。
noip2014倒数第四天,我的最后一届noip,离退役还有六天。
最短路,四种算法,dijstra,spfa,floyd,bellman-ford,今天只讲两种,dij 和 bellman-ford
dijstra
其实单纯的dij和prim类同,但是dij的精妙在于它可以使用堆优化ヽ(✿゚▽゚)ノ
然后。。。好像就没有可以讲的了,dij要用邻接矩阵,一般要用n^2,可以用堆优化到log级别……
邻接矩阵比较容易理解,不过储存范围有限,最多只能开到千级别,其实我一般都打spfa+链表的……不过rqnoj有一道题专卡链表,链表确实容易被卡,如果可以,写dij+堆是最好的选择……
如果边较多一般选择用dij,因为那种类似生成树的边集非常轻松的卡过了spfa+链表……
不过dij无法处理负权。
Var
n,m,num,a,b,c,i,j:longint;
ed,from,val,son,next,intoout,outtoin,dis,d:array[1..2000001]of longint;
visit:array[1..2000001]of 0..1;
Procedure swap(var a,b:longint);
var
temp:longint;
begin
temp:=a;
a:=b;
b:=temp;
end;
Procedure down(l:longint);
begin
while ((l<n)and (d[l]>d[l shl 1+1]))or ((l<n)and (d[l]>d[l shl 1])) do
if d[l shl 1+1]>d[l shl 1]
then begin
swap(d[l shl 1+1],d[l]);
swap(intoout[l],intoout[l shl 1+1]);
swap(outtoin[intoout[l]],outtoin[intoout[l shl 1+1]]);
l:=l shl 1+1;
end
else begin
swap(d[l shl 1],d[l]);
swap(intoout[l],intoout[l shl 1]);
swap(outtoin[intoout[l]],outtoin[intoout[l shl 1]]);
l:=l shl 1;
end;
end;//与普通堆操作相同,只是还要留心对映射表的操作
Procedure up(l:longint);
begin
while(l>1) and(d[l shr 1]>d[l]) do
begin
swap(d[l shr 1],d[l]);
swap(intoout[l],intoout[l shr 1]);
swap(outtoin[intoout[l]],outtoin[intoout[l shr 1]]);
l:=l shr 1;
end;
end;//与普通堆操作相同,只是还要留心对映射表的操作
Procedure dijkstra(x:longint);
var
i,len,edd:longint;
begin
fillchar(d,sizeof(d),$7f);
fillchar(dis,sizeof(dis),$7f);
fillchar(visit,sizeof(visit),0);//数组的初始化,不解释
for i:=1 to n do
begin
outtoin[i]:=i;//表示堆外映射堆内
intoout[i]:=i;//表示堆内映射堆外
end;//为了加快处理速度,我们可以开一张映射表以代替路径数组的维护
d[x]:=0;//对入点首先进行拓展
len:=n;//由于后面需要对点书进行操作与修改,此处用len记录n以方便操作
up(x);//对现在的堆进行维护PS.本步不可少,即使是本程序中,我们也可以看到,0不一定在第一个位置。
while (visit[n]=0)and(len>0) do//ps.由于可以理解为求1到n的最短路,因此当第n点被访问时,程序已经结束。当题目大意与本题不符合时,(visit[n]=0)应舍去。
begin
edd:=intoout[1];//以当前点为起点,记录拓展花费的最小代价的点
dis[edd]:=d[1];//将该点记录到最小路径的数组中
visit[intoout[1]]:=1;//表示该点已经被访问
j:=son[edd];
d[1]:=d[len];
intoout[1]:=intoout[len];
outtoin[intoout[1]]:=1;
dec(len);//以上都为删堆的操作
down(1);//一轮操作完了,接着对堆进行维护
while j<>0 do
begin
if (visit[ed[j]]=0)and(val[j]+dis[edd]<d[outtoin[ed[j]]])
then begin
d[outtoin[ed[j]]]:=val[j]+dis[edd];
up(outtoin[ed[j]]);
end;//拓展(更新)到达堆中点的最短路径
j:=next[j];//对下一条边进行拓展
end;
end;
end;
Begin
readln(n,m);//读入点数与边数
num:=0;//num用于记录边的条数
for i:= 1 to m do
begin
read(a,b,c);//读入a,b,表示两点之间有通路,且路径长度为c
inc(num);//每读入一条边,边数自然要加一
from[num]:=a;//from数组用于记录第num条边的出点,相当于是树中的父节点。PS.在经典的最短路径求法中,这步可以不写
ed[num]:=b;//ed数组用于记录第num条边的终点
val[num]:=c;//val用于记录第num条边的路径长度
next[num]:=son[a];
son[a]:=num;//链表记边时,插入的元素要放在链表(son)首部,同时,将原来的首部放在新元素的后面(next)
inc(num);//同样的,本题中需要双向记边
from[num]:=b;
ed[num]:=a;
val[num]:=c;
next[num]:=son[b];
son[b]:=num;
end;//那么到这里,读入就完成了。接下来就是dijkstra的主要部分了
dijkstra(1);//最短路径问题,其实也可以转化为1——n之间的最短路。
write(dis[n]);//本题也可以转化为1——n之间的最短路,因此只要输出n的最短路即可
End.
end;//那么到这里,读入就完成了。接下来就是dijkstra的主要部分了
dijkstra(1);//最短路径问题,其实也可以转化为1——n之间的最短路。
write(dis[n]);//本题也可以转化为1——n之间的最短路,因此只要输出n的最短路即可
End.
dij的堆实际上是贪心部分的转化
代码来源于我一位已经退役的同学2013年的博文,读来真令人感慨万千
http://blog.sina.com.cn/s/blog_69e5b8a20101ci5k.html
我搜索资料时,没想到他还写过这类文章,2013年时,我们大部分人还在spfa和floyd之间挣扎,我在电脑前重复默写spfa的代码,那场景还历历在目,没想到我这位蒟蒻仍然拼搏在noip赛场上,这样的一位神犇却退役了。
bellman-ford
可以允许回路出现,其实spfa也可以判回路,设定一个点的出现次数,或者用拓扑?
bellman-ford的思想最重要的是松驰(?)其实只是维护边最短
if dis[u] + w < dis[v] then
begin
dis[v] := dis[u] + w;
pre[v] := u;
end
ford 的效率和读入的边数有关,效率其实不是很高。
noip应该不会卡链表吧ovo
掌握好spfa是最重要的,spfa的代码要远远短于dij,考试的时候如果堆打wa了,我们是没有那么多时间去调的。
- 最短路?那是什么 °▽°
- 那是什么
- Exercise 10: 那是什么?
- 习题10 那是什么
- 那是最美
- 构建它,他们会来 - 那是什么
- 练习10:那是什么鬼= =、
- 笨办法10那是什么?-转义
- 最短路 & 次短路
- 最短路
- 最短路
- 最短路
- 最短路
- 最短路
- 最短路
- 最短路
- 最短路
- 最短路
- 张孝祥老师java课程_子类对象的实例化过程
- leetcode Minimum Path Sum
- fscant 实例
- hdu-5018
- distributor之Software Generated Interrupt Register, GICD_SGIR
- 最短路?那是什么 °▽°
- Struts2 结果和结果类型
- interView - singleton的几种写法
- Jquery Ajax 登录,服务端分别为 aspx,ashx,asmx
- 兄弟郊游问题
- VNC介绍(第一篇)
- spring controller返回json字符串 @responsebody 乱码
- 一条网线,一个交换机,两台电脑通过拨号上网 ;一台路由器,多台电脑;
- android Application类的详细介绍