Floyd算法及其进阶
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Fl oyd算法及其进阶
一、Floyd-Warshall算法
这个算法没什么可说的,我们一般称之为Floyed〔弗洛伊德〕算法,那么这个算法是干什么的呢?我们先来看这样一道题:
【例1】Doctor Zhang在育才上学,可是上学的时光实在是太郁闷了,除了每天要上各种语文数学英语物理化学生物之外还要上计算机竞赛还有自主招生培训??〔Dr Zhang表示很悲剧的说??〕,于是乎神棍的Doctor决定双周末在计算机小屋留校〔其实是为了晚上出去包宿玩“山口山〞〕,又于是乎Doctor悲剧的进入了艾泽拉斯世界,可是他悲剧的发现CTM开了以后自己取过的地方都不认识了,迷茫的医生来到了飞行点,但飞行点的猥琐怪蜀黍告诉医生他只知道有直达路线的两个地区之间的飞行价格〔比方从幽暗城到银月城消费1银4铜,从幽暗城到东瘟疫之地消费68铜,猥琐怪蜀黍并不知道从银月城到东瘟疫之地要花多少钱??真塔玛莎~~~~〕现在请你设计一个程序,帮助医生求出所有两座城市之间的最省钱的飞行方式〔医生是法师,但在此题中绝对不允许开门传送!!!!〕 #注:艾泽拉斯世界1金=100银 1银=100铜输入格式:输入文件为warcraft.in.,其中:
第一行为整数n,表示共有n个不同的飞行点。
第二行为整数m,表示共有m 条直达路径
第三行开始接下来m行,每行有5个数字x y g s c表示从x到y需要g金s 银c
铜〔g s cf[I,k]+f[j,k] then
F[I,j]:=f[I,k]+f[k,j];
应该说这是我这辈子见到的最漂亮的代码了,真是美妙的算法!
【例1】标程如下: program floyd_warcraft; var
m,n,x,y,g,s,c,i,j,k,p:longint;
map:array[1..1000,1..1000] of integer; begin
assign(input,'warcraft.in');
assign(output,'warcraft.out'); reset(input);
rewrite(output);
readln(n); readln(m);
fillchar(map,sizeof(map),maxint); for i:=1 to m do
begin
readln(x,y,g,s,c);
map[x,y]:=10000*g+1000*s+c; map[y,x]:=map[x,y]; end;
for k:=1 to n do for i:=1 to n do for j:=1
to n do begin
if map[i,j]>map[i,k]+map[k,j]
then map[i,j]:=map[i,k]+map[k,j]; end; for i:=1 to n do begin
for j:=1 to n do begin
p:=map[i,j];
g:=map[i,j] div 10000; s:=map[i,j] mod 10000; c:=s mod 100; s:=s div 100;
writeln(g,'GOLD',s,'SLIVER',c,'COPPER',' '); end; writeln; end;
close(input);
close(output); end.
那么现在我们把题目改变一下,其实floyd也有别的用途,比方:
【例2】现在医生想知道每条路最省钱的路径到底是怎么走的,你能改变【例
1】中的程序并使其输出从x到y的最短路径如“x->a->b->y〞。
请你思考
留出了5行的思考空间,对于这样的问题,doctor首先想到了子问题的递归
方式〔当然,还有更好一点的方法〕请看下面的对话:
(D:doctor,N:nurse;)
D:问下从x到y得经过哪里? N:我只知道经过了K D:那从x到k呢?
N:经过了kk节点
D:从x到kk和从kk到k之间有没有经由呢? N:没有了,都是直达; D:那从k到y有没有? N:没有了?? D:真的没有了? N:真的没有了! D:你确定? N:~~~??确定?? D:真的假的? N:??
D:矮油??你倒是说话呀!
然后nurse一记华美丽的炮拳轰了过来
被华美丽轰飞的doctor又坚挺的站了起来!饿??好凶猛的护士!其实不用问这么多问题的,不用递归亦可以,其实我们只要在关键的地方加上一句就好了! Route:array[1..maxn] of ansistring;
For k:=1 to n do For i:=1 to n do
For j:=1 to n do
If map[I,j]>map[I,k]+map[k,j] then
Begin
Map[I,j]:= map[I,k]+map[k,j];
Route[I,j]:=route[I,k]+’->’+route[k,j];
End;
对floyd算法的评价:首先第一点,这个算法用到的DP的思想是值得肯定的,应该说是非常漂亮的程序代码,其关键局部只有短短的五行,给记忆带来了很大的便利〔这是所有图算法中最好记得了!〕同时也是最为神奇的算法之一。
但该算法也有其局限性:比附只能通过邻接矩阵来实现,浪费空间同时也浪费时间,邻接表哪怕是用志卿神棍的二维数组写法也是很快的。
其次,floyd的时间复杂度足有O〔N 〕这也就意味着我们只有10 ~10 次每秒运算速度的测评机只能算到1000个以内的节点,但对于我们一般的竞赛题来说很快就tle了,超时就是悲剧,而且大多数情况下我们都不会选择这种算法,更多的时候我们只需要知道从确定某一点到另外一点的最短距离,这样我们就有必要介绍一下
dijkstra算法和bellman-ford算法还有非常神的spfa算法〔这个可是中国人的创造哦!@_@〕
日啊!floyd就是这么蛋疼啊@
蛋疼有木有!有木有~floyd你伤不起啊!
【floyd进阶思想!!】求最小环!【Vijos 1046】观光旅游〔floyd求最小环〕【背景 Background】
湖南师大附中成为百年名校之后,每年要接待大批的游客前来参观。
学校认为大力开展旅游业,可以带来一笔可观的收入。
【描述 Description】
学校里面有N个景点。
两个景点之间可能直接有道路相连,用Dist[I,J]表示它的长度;否那么它们之间没有直接的道路相连。
这里所说的道路是没有规定方向的,也就是说,如果从I到J有直接的道路,那么从J到I也有,并且长度与之相等。
学校规定:每个游客的旅游线路只能是一个回路〔好霸道的规定〕。
也就是说,游客可以任取一个景点出发,依次经过假设干个景点,最终回到起点。
一天,Xiaomengxian决定到湖南师大附中旅游。
由于他实在已经很累了,于是他决定尽量少走一些路。
于是他想请你——一个优秀的程序员——帮他求出最优的路线。
怎么样,不是很难吧?〔摘自《郁闷的出纳员》〕【输入格式 Input Format】
输入中有多组数据。
请用SeekEof判断是否到达文件结束。
对于每组数据:第一行有两个正整数N,M,分别表示学校的景点个数和有多少对景点之间直接有边相连。
〔N朴素的算法:
令e(u,v)表示u和v之间的连边,再令min(u,v)表示,删除u和v之间的连边之后,u和v之间的最短路
最小环那么是min(u,v) + e(u,v),时间复杂度是EV2。
改良的方法:在floyd的同时,顺便算出最小环 g[i][j]=(i,j之间的边长) dist:=g;
for k:=1 to n do begin
for i:=1 to k-1 do for j:=i+1 to k-1 do
answer:=min(answer,dist[i][j]+g[i][k]+g[k][j]); for i:=1 to n do
for j:=1 to n do
dist[i][j]:=min(dist[i][j],dist[i][k]+dist[k][j]); end;
关于算法的证明:
一个环中的最大结点为k(编号最大),与他相连的两个点为i,j,这个环的最短长度为g[i][k]+g[k][j]+i到j的路径中,所有结点编号都小于k的最短路径长度
根据floyd的原理,在最外层循环做了k-1次之后,dist[i][j]那么代表了i到j的路径中,所有结点编号都小于k的最短路径
综上所述,该算法一定能找到图中最小环。
以上文段选自〔绍兴县柯桥中学黄劲松《图论中的圈与块》〕。