最小生成树

来源:互联网 发布:db2关闭数据库 编辑:程序博客网 时间:2024/06/05 16:33

最小生成树

——————————————————————————————————————
第二篇文章!!!!!
_____________________________________________________________________________________________________________________________________________________________
(1)prim算法(heap优化)
prim是一种最小生成树算法,它类似于dijkstra,基于一种贪心思想,每次选出可行的最短边加入生成树集合,这样计算出最后的结果。话不多说,因为其并不复杂,又已经有了dijkstra的铺垫(不知道可以看我的第一篇文章:单源最短路径),于是乎!我们直接上堆优化:
【代码】
<span style="font-size:18px;">program prim;type point=^node;     node=record v,w:longint; next:point; end;     ex=record w,i:longint; end;const maxn=10000;var p:point;    x:ex;    n,m,i,j,k,l,len,sum,ans:longint;    a:array[1..maxn] of point;    d:array[1..maxn] of longint;    v:array[1..maxn] of boolean;    heap:array[0..maxn*2+1] of ex;                                       //类似dijkstra的说明procedure swap(var x,y:ex);                                              //元素交换var t:ex;begin  t:=x;x:=y;y:=t;end;procedure gettop(var x:ex);                                             //取堆顶var k:longint;    p:ex;begin  x:=heap[1];heap[1]:=heap[len];heap[len].w:=maxlongint;len:=len-1;  k:=1;  while k<=len div 2 do    begin      if (heap[k].w<heap[2*k].w) and (heap[k].w<heap[2*k+1].w) then break;      if heap[2*k].w<=heap[2*k+1].w then begin swap(heap[k],heap[2*k]); k:=k*2; end        else begin swap(heap[k],heap[2*k+1]); k:=2*k+1; end;    end;end;procedure put(x,l:longint);                                              //插入元素var k:longint;begin  len:=len+1;heap[len].w:=x;heap[len].i:=l;  k:=len;  while (k div 2>0) and (heap[k div 2].w>heap[k].w) do    begin      swap(heap[k div 2],heap[k]);      k:=k div 2;    end;end;procedure init;                                                         //读入begin   readln(n,m);  for i:=1 to maxn do a[i]:=nil;  for l:=1 to m do    begin      readln(i,j,k);      new(p);p^.v:=j;p^.w:=k;p^.next:=nil;p^.next:=a[i];a[i]:=p;      new(p);p^.v:=i;p^.w:=k;p^.next:=nil;p^.next:=a[j];a[j]:=p;    end;end;procedure prepare;                                                     //初始化begin  fillchar(v,sizeof(v),false);v[1]:=true;  fillchar(d,sizeof(d),$7f div 3);  new(p);p:=a[1];while p<>nil do begin d[p^.v]:=p^.w;p:=p^.next; end;d[1]:=0;  for i:=1 to maxn*2+1 do with heap[i] do begin w:=0;i:=0; end;  heap[1].w:=0;heap[1].i:=1;                                          //最小生成树不存在源点和终点,即所有点都要进去,所以我们为了方便,先将点1加入生成树集合,并入堆  len:=1;for i:=2 to n do put(d[i],i);  ans:=0;sum:=1;end;procedure main;                                                       //prim算法begin  repeat    gettop(x);    if v[x.i] then continue;    sum:=sum+1;v[x.i]:=true;ans:=ans+d[x.i];    new(p);p:=a[x.i];    while p<>nil do      begin        if (not v[p^.v]) and (p^.w<d[p^.v]) then          begin            d[p^.v]:=p^.w;            put(d[p^.v],p^.v);          end;        p:=p^.next;      end;  until sum=n;end;begin  assign(input,'prim.in');reset(input);  assign(output,'prim.out');rewrite(output);  init;  prepare;  main;                                                                     //调用一堆过程  write(ans);                                        close(input);close(output);end.</span>



(2)kruskal算法
思想是:选择满足条件的最小边依次加入,有回路就掐,没有就进。
【代码】
<span style="font-size:18px;">program kruskal;type node=record u,v,w:longint; end;const maxn=10000;maxm=20000;var  n,m,i,j,k,l,x,y,ans:longint;  a:array[1..maxm] of node;                                           //边集数组</span>
<span style="font-size:18px;">  f:array[1..maxn] of longint;                                        //祖宗procedure qsort(l,r:longint);                                        //对权值排序var i,j,x:longint;    y:node;begin  i:=l;j:=r;x:=a[(i+j) div 2].w;  repeat    while x>a[i].w do i:=i+1;    while x<a[j].w do j:=j-1;    if i<=j then      begin        y:=a[i];a[i]:=a[j];a[j]:=y;        i:=i+1;j:=j-1;      end;  until i>j;  if i<r then qsort(i,r);  if l<j then qsort(l,j);end;function gen(x:longint):longint;begin  if f[x]=0 then exit(x);  gen:=gen(f[x]);  f[x]:=gen;end;begin  assign(input,'kruskal.in');reset(input);  assign(output,'kruskal.out');rewrite(output);   readln(n,m);  for l:=1 to m do readln(a[l].u,a[l].v,a[l].w);                           //读入  qsort(1,m);  fillchar(f,sizeof(f),0);j:=0;                                           //初始化  for i:=1 to m do                                                        //kruskal    begin      x:=gen(a[i].u);y:=gen(a[i].v);      if x<>y then        begin          f[x]:=y;j:=j+1;          ans:=ans+a[i].w;        end;      if j=n-1 then break;                                               //n-1条边已完成,退出    end;  write(ans);                                                            //输出  close(input);close(output);end.</span>

以上就是最小生成树的算法,讲完了,再见。
1 0
原创粉丝点击