Dijkstra堆优化+边表存储

本文详细阐述了Dijkstra算法结合Heap数据结构的优化过程,通过建立小根堆并不断维护,显著提高了处理大数据集时的效率。文章还介绍了如何使用边表或前向星类数据结构存储信息以进一步优化算法性能。

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

算法:DIJ+HEAP

步骤:建一个小根堆,把权值都放进去,每次都在堆里面取出堆首,然后不断的维护这个堆,时间复杂度是O(nlogn),比之前O(n²)的算法快了不少。对于大数据时采用边表或前向星类似的数据结构存,能优化不少。

 

program NDK1068;

const
 maxn=10000;
 maxm=1000000;
 
type
 atp=record
  y,next,dis:longint;
 end;
 agp=record
  x,data:longint;
 end;

var
 map:array [0..maxm] of atp;{map记录边的信息。}
 v:array [0..maxn] of agp;{v[i].x表示在i位置上的数的原来的位置,v[i].data表示到堆中这个点的最小权值。}
 first:array [0..maxn] of longint;{first记录边的信息。}
 linkv:array [0..maxn] of longint;{linkv[i]表示原位置上的数现在在堆里的位置。实际上与v[i].x形成了相互的映射。}
 n,m,tot,st,ed:longint;
 
procedure init;
var
 i,x,y,dis:longint;
 temp:agp;
begin
 fillchar(first,sizeof(first),0);
 fillchar(map,sizeof(map),0);
 readln(n,m);
 for i:=1 to m do
  begin
   readln(x,y,dis);
   inc(tot);
   map[tot].y:=y;
   map[tot].dis:=dis;
   map[tot].next:=first[x];
   first[x]:=tot;
  end;
 for i:=1 to n do linkv[i]:=i;{初始化。}
 for i:=1 to n do
  begin
   v[i].x:=i;
   v[i].data:=maxlongint;
  end;
 readln(st,ed);
 {这里首先要把起点和堆首交换一下,因为先设起点为最小的点。}
 temp:=v[st];
 v[st]:=v[1];
 v[1]:=temp;
 v[1].data:=0;
end;

procedure ad_up(x:longint);
var
 temp:agp;
begin
 while x shr 1>=1 do
  begin
   if v[x].data<v[x shr 1].data then
    begin
     temp:=v[x];
     v[x]:=v[x shr 1];
     v[x shr 1]:=temp;
     {改变原位置上的数的现在的位置。}
     linkv[v[x].x]:=x;
     linkv[v[x shr 1].x]:=x shr 1;
     x:=x shr 1;
    end
   else break;
  end;
end;

procedure ad_down(i,m:longint);
var
 temp:agp;
begin
 while i shl 1<=m do
  begin
   i:=i shl 1;
   if (v[i+1].data<v[i].data) and (i<m) then inc(i);
   if v[i].data<v[i shr 1].data then
    begin
     temp:=v[i];
     v[i]:=v[i shr 1];
     v[i shr 1]:=temp;
     {同上。}
     linkv[v[i].x]:=i;
     linkv[v[i shr 1].x]:=i shr 1;
    end
   else break;
  end;
end;

procedure dij;
var
 i,min,minp,t:longint;
 temp:agp;
begin
 for i:=1 to n do
  begin
   {取最小点,最小权值,同时把堆首跟堆尾元素进行交换。}
   minp:=v[1].x;
   min:=v[1].data;
   linkv[v[1].x]:=n-i+1;
   linkv[v[n-i+1].x]:=1;
   temp:=v[1];
   v[1]:=v[n-i+1];
   v[n-i+1]:=temp;
   {维护堆。}
   ad_down(1,n-i);
   t:=first[minp];
   if min<>maxlongint then{判断能否到达堆首。}
    begin
     while t<>0 do
      begin
       if (map[t].dis+min<v[linkv[map[t].y]].data) and (linkv[map[t].y]<=n-i) then{后面的判断保证了要扩展的点在堆里。即尚未扩展。}
        begin
         v[linkv[map[t].y]].data:=map[t].dis+min;
         ad_up(linkv[map[t].y]);{上调维护。}
        end;
       t:=map[t].next;
      end;
    end
   else break;
  end;
end;

begin
 assign(input,'NDK1068.in'); reset(input);
 assign(output,'NDK1068.out'); rewrite(output);
 
 init;
 dij;
 if v[linkv[ed]].data<>maxlongint then writeln(v[linkv[ed]].data) else writeln('No Solution!');{输出。}
 
 close(input); close(output);
end.


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值