[0516]图论算法学习笔记 (Ⅱ)

本文介绍了四种解决最短路径问题的方法:动态规划法、Dijkstra算法、SPFA算法及Floyd算法。通过一个实例问题——小呆打车,详细展示了如何使用Dijkstra算法找到两点间的最短路径。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最短路径问题可用4种方法解决:
1.动态规划法(标号法)
2.Dijkstra算法
3.SPFA算法
4.Floyd算法
前三种算法的时间复杂度一般是O(n²)而Floyd算法的时间复杂度为O(n³)。
不过,Floyd算法适用于APSP(All Pairs Shortest Paths),是一种动态规划算法,稠密图效果最佳,边权可正可负。此算法简单有效,由于三重循环结构紧凑,对于稠密图,效率要高于执行|V|次Dijkstra算法。  优点:容易理解,可以算出任意两个节点之间的最短距离,代码编写简单。  
缺点:时间复杂度比较高,不适合计算大量数据。 
例题: From Admin 
A层次第二讲:小呆打车(taxi)  
   
 背景 Background  
   A层次第二讲第二题  
      
 描述 Description   
     寒假里,小呆要去位于A市的皮球家拜年。小呆来到A市的车站,买了一张A市的地图,他发现这里的地形非常的复杂。A市的街道一共有N个路口,M条道路,每条道路连接着两个路口,并且有各自的长度。目前,小呆所在的车站位于编号为1的路口,而皮球家所在的路口编号为N,小呆准备打出租车去,当然,路程越小,付的钱就越少。问题摆在眼前:请帮助小呆寻找一条最短路径,使得他可以花最少的钱到达皮球家。 
      
 输入格式 Input Format  
     输入文件的第一行有两个整数N;M,(N<=1000<=M)分别代表路口数和街道数。以下有M行用以描述各个街道,每行有三个数字P1;P2;L,分别代表此街道起点编号,此街道终点编号以及此街道的长度。保证所给的数据可以构成连通图。  
     
 输出格式 Output Format  
     输出文件中只要求出现一行,一个整数,说明最短路径的长度(<=maxlongint)。

program P1012_dijkstra;
const max=1000;
var g:array[1..1000,1..1000]of integer;
    s:array[1..max]of boolean;
    dist:array[1..max]of longint;
    path:array[1..max]of integer;
    i,j,k,n,min,vj:longint;
procedure print(i:integer);
var pre:integer;
begin
if i= 1 then write(1)
else begin print(path[i]);write('->',i);end;
end;
procedure init;
var i,j,a,b,s:integer;
begin
  readln(n,s);
  for i:=1 to n do
      for j:=1 to n do
          if (i<>j) then g[i,j]:=maxint;
  for  i:=1 to s do
       readln(a,b,g[a,b]);
end;
begin
    init;
    fillchar(s,sizeof(s),false);
    fillchar(path,sizeof(path),1);
    for i:=1 to n do dist[i]:=g[1,i];
    s[1]:=true;
    for k:=1 to n-2 do
      begin
        min:=maxint;
        for j:=1 to n do
          if (dist[j]<min)and not s[j] then
             begin
               min:=dist[j];
               vj:=j;
             end;
          s[vj]:=true;
          for j:=1 to n do
             if min+g[vj,j]<dist[j] then
             begin
             dist[j]:=min+g[vj,j];
             path[j]:=vj;
             end;

      end;
      //print(n);
      writeln(dist[n]);
end.
const maxn=10000;
      maxm=100000;
var
    head,dis:array[0..maxn]of longint;
    u:array[0..maxn]of boolean;
    next,v,c:array[0..maxm]of longint;
    d:array[0..1000000]of longint;
    top,i,n,m,x,y,z,k:longint;
procedure add(x,y,z:longint);
begin
     inc(top);v[top]:=y;c[top]:=z;next[top]:=head[x];head[x]:=top;
end;
procedure spfa;
var l,r:longint;
begin
     fillchar(dis,sizeof(dis),$3f);
     dis[1]:=0;l:=0;r:=1;d[1]:=1;
     repeat
           inc(l);
           k:=head[d[l]];
           while k<>0 do
                 begin
                 if dis[v[k]]>dis[d[l]]+c[k] then
                    begin
                    dis[v[k]]:=dis[d[l]]+c[k];
                    if not u[v[k]] then
                       begin
                       inc(r);
                       d[r]:=v[k];
                       u[v[k]]:=true;
                       end;
                    end;
                 k:=next[k];
                 end;
           u[d[l]]:=false;
     until l=r;
end;
begin
     readln(n,m);
     for i:=1 to m do
         begin
         readln(x,y,z);
         add(x,y,z);
         end;
     spfa;
     writeln(dis[n]);
end.


Accepted code:
var   d,sy:array [0..1001] of longint;   s,a,b,w:array [0..1000001] of longint;   v:array [0..1001] of boolean;   n,m,now,l,r,i,y:longint; procedure sort(l,r:longint);   var     i,j,x:longint;   begin     i:=l;j:=r;x:=a[random(r-l+1)+l];     repeat       while a[i]<x do inc(i);       while x<a[j] do dec(j);       if i<=j then         begin           y:=a[i];a[i]:=a[j];a[j]:=y;           y:=b[i];b[i]:=b[j];b[j]:=y;           y:=w[i];w[i]:=w[j];w[j]:=y;           inc(i);dec(j);         end;     until i>j;     if j>l then sort(l,j);     if i<r then sort(i,r);   end; begin   readln(n,m);   for i:=1 to m do     begin       readln(a[i],b[i],w[i]);       a[i+m]:=b[i];b[i+m]:=a[i];w[i+m]:=w[i];     end;   randomize;   m:=m*2;   sort(1,m);   now:=0;i:=1;   repeat     while (i<=m) and (a[i]<=now) do inc(i);     sy[now+1]:=i;     inc(now);   until now>=n;   d[1]:=0;   for i:=2 to n do     d[i]:=maxlongint div 2;   l:=1;r:=1;s[1]:=1;   while l<=r do     begin       i:=sy[s[l]];       while a[i]=s[l] do         begin           if d[b[i]]>d[a[i]]+w[i] then             begin               d[b[i]]:=d[a[i]]+w[i];               if not v[b[i]] then                 begin                   inc(r);                   s[r]:=b[i];                   v[b[i]]:=true;                 end;             end;           inc(i);         end;       v[s[l]]:=false;       inc(l);     end;   writeln(d[n]); end.

转载于:https://www.cnblogs.com/shy-/archive/2012/05/16/2504638.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值