《啊哈!算法》第8章详解

一. 最小生成树

(1).krusakal算法

     参考程序:

var

  n,count,ans,m,i,p,q:longint;

  a,b,c,f:array[0..100000]of longint;

function find(x:longint):longint;

begin

  if f[x]<>x then f[x]:=find(f[x]);

  exit(f[x]);

end;

procedure qsort(l,r:longint);

var

  i,j,x,t:longint;

begin

  i:=l;j:=r;x:=c[(l+r)shr 1];

  repeat

    while c[i]<x do i:=i+1;

    while c[j]>x do j:=j-1;

    if i<=j then

     begin

       t:=a[i];a[i]:=a[j];a[j]:=t;

       t:=b[i];b[i]:=b[j];b[j]:=t;

       t:=c[i];c[i]:=c[j];c[j]:=t;

       i:=i+1;j:=j-1;

     end;

  until i>j;

  if i<r then qsort(i,r);

  if j>l then qsort(l,j);

end;

begin

  readln(n,m);

  for i:=1 to m do

   readln(a[i],b[i],c[i]);

  qsort(1,m);

  for i:=1 to n do f[i]:=i;

  for i:=1 to m do

   begin

     p:=find(a[i]);q:=find(b[i]);

     if p<>q then

      begin

        ans:=ans+c[i];

        f[q]:=p;

        count:=count+1;

        if count=n-1 then break;

      end;

    end;

   write(ans);

end.

(2).prim+heap

比较容易理解却有可能退化的参考程序:

type

  point=^node;

  node=record

        v,w:longint;

        next:point;

       end;

  rec=record v,w:longint;end;

var

  p:point;

  n,l,m,ans,i,tt,x,y,z:longint;

  h:array[0..100000]of rec;

  a:array[0..100000]of point;

  used:array[0..100000]of boolean;

  dis:array[0..100000]of longint;

procedure build(x,y,z:longint);

var

  p:point;

begin

  new(p);

  p^.v:=y;p^.w:=z;

  p^.next:=a[x];

  a[x]:=p;

end;

procedure push(x,y:longint);

var

  t:rec;

  d,s:longint;

begin

  l:=l+1;h[l].w:=x;h[l].v:=y;s:=l;

  while s>1 do

   begin

     d:=s shr 1;

     if h[d].w>h[s].w then

      begin

        t:=h[d];h[d]:=h[s];h[s]:=t;

        s:=d;

      end

     else break;

   end;

end;

function pop:longint;

var

  t:rec;

  d,s:longint;

begin

  pop:=h[1].v;h[1]:=h[l];l:=l-1;d:=1;

  while 2*d<l do

   begin

     s:=2*d;

     if (h[s+1].w<h[s].w)and(s<l) then s:=s+1;

     if h[d].w>h[s].w then

      begin

        t:=h[d];h[d]:=h[s];h[s]:=t;

        d:=s;

      end

     else break;

   end;

end;

begin

  readln(n,m);

  for i:=1 to m do

   begin

     readln(x,y,z);

     build(x,y,z);

     build(y,x,z);

   end;

  fillchar(dis,sizeof(dis),$7f shr 2);

  p:=a[1];

  while p<>nil do

   begin

     dis[p^.v]:=p^.w;

     push(p^.w,p^.v);

     p:=p^.next;

   end;

  used[1]:=true;

  dis[1]:=0;

  for i:=1 to n-1 do

   begin

     repeat

       tt:=pop;

     until not used[tt];

     used[tt]:=true;

     ans:=ans+dis[tt];

     p:=a[tt];

     while p<>nil do

      begin

        if (not used[p^.v])and(p^.w<dis[p^.v]) then

         begin

           dis[p^.v]:=p^.w;

           push(dis[p^.v],p^.v);

         end;

        p:=p^.next;

      end;

   end;

  write(ans);

end.

               

 

                  二.图的割点

原理:tarjan算法,一般用于图的强连通分量分解

参考程序:

var

  cnt:longint;

  low,dfn,head:array[0..10000]of longint;

  e:array[0..10000]of record

                       v,next:longint;

                       end;

  n,m,time,i,a,b,root:longint;

  flag:array[0..10000]of boolean;

function min(a,b:longint):longint;

begin

  if a<b then exit(a);

  exit(b); 

end;

procedure insert(x,y:longint);

begin

  cnt:=cnt+1;

  e[cnt].v:=y;

  e[cnt].next:=head[x];

  head[x]:=cnt;

end;

procedure dfs(u,father:longint);

var

  i,child:longint;

begin

  time:=time+1;

  dfn[u]:=time;low[u]:=time;

  i:=head[u];child:=0;

  while i>0 do

   begin

     if dfn[e[i].v]=0 then

      begin

        child:=child+1;

        dfs(e[i].v,u);

        low[u]:=min(low[u],low[e[i].v]);

        if (u<>root)and(low[e[i].v]>=dfn[u]) then

         flag[u]:=true;

        if (u=root)and(child=2) then

         flag[u]:=true;

      end

     else if (e[i].v<>father) then low[u]:=min(low[u],dfn[e[i].v]);

     i:=e[i].next;

   end;

end;

begin

  readln(n,m);

  for i:=1 to m do

   begin

     readln(a,b);

     insert(a,b);

     insert(b,a);

   end;

  root:=1;

  dfs(1,root);

  for i:=1 to n do

   if flag[i] then write(i,' ');

end.

 

 

 

                  三.图的割边

原理同割点。

参考程序:

var

  cnt:longint;

  low,dfn,head:array[0..10000]of longint;

  e:array[0..10000]of record

                       v,next:longint;

                       end;

  n,m,time,i,a,b,root:longint;

  flag:array[0..10000]of boolean;

function min(a,b:longint):longint;

begin

  if a<b then exit(a);

  exit(b); 

end;

procedure insert(x,y:longint);

begin

  cnt:=cnt+1;

  e[cnt].v:=y;

  e[cnt].next:=head[x];

  head[x]:=cnt;

end;

procedure dfs(u,father:longint);

var

  i:longint;

begin

  time:=time+1;

  dfn[u]:=time;low[u]:=time;

  i:=head[u];

  while i>0 do

   begin

     if dfn[e[i].v]=0 then

      begin

        dfs(e[i].v,u);

        low[u]:=min(low[u],low[e[i].v]);

        If low[e[i].v]>dfn[u] then

           Writeln(u,-,e[i].v);

      end

     else if (e[i].v<>father) then low[u]:=min(low[u],dfn[e[i].v]);

     i:=e[i].next;

   end;

end;

begin

  readln(n,m);

  for i:=1 to m do

   begin

     readln(a,b);

     insert(a,b);

     insert(b,a);

   end;

  root:=1;

  dfs(1,root);

end.

 

                  四.二分图匹配

书上的方法:连锁反应(反复神搜)

超快标程(网络流dinic算法):

type

  edge=record

        tt,v,next:longint;

       end;

const

  INF=maxlongint shr 2;

var

  cnt,x,y,z,start,stop,n,m,maxflow,i:longint;

  h,a,q:array[0..100000]of longint;

  e:array[0..200000]of edge;

procedure insert(u,v,w:longint);

begin

  cnt:=cnt+1;

  e[cnt].tt:=v;

  e[cnt].v:=w;

  e[cnt].next:=a[u];

  a[u]:=cnt;

end;

function min(a,b:longint):longint;

begin

  if a<b then exit(a);

  exit(b);

end;

function bfs:boolean;

var

  head,i,now,tail:longint;

begin

  fillchar(h,sizeof(h),$ff);

  head:=0;tail:=1;

  q[1]:=start;h[start]:=0;

  while head<tail do

   begin

     head:=head+1;

     now:=q[head];

     i:=a[now];

     while i>0 do

      begin

        if (e[i].v>0)and(h[e[i].tt]=-1) then

         begin

           tail:=tail+1;

           q[tail]:=e[i].tt;

           h[e[i].tt]:=h[now]+1;

         end;

        i:=e[i].next;

      end;

   end;

  if h[stop]=-1 then exit(false);

  exit(true);

end;

function dfs(x,f:longint):longint;

var

  w,used,i:longint;

begin

  if x=stop then exit(f);

  used:=0;i:=a[x];

  while i>0 do

   begin

     if (e[i].v>0)and(h[e[i].tt]=h[x]+1) then

      begin

        w:=f-used;

        w:=dfs(e[i].tt,min(e[i].v,w));

        e[i].v:=e[i].v-w;

        e[i xor 1].v:=e[i xor 1].v+w;

        used:=used+w;

        if used=f then exit(f);

      end;

     i:=e[i].next;

   end;

  if used=0 then h[x]:=-1;

  exit(used);

end;

begin

  readln(n,m);

  for i:=1 to m do

   begin

     readln(x,y);

     insert(x,y,1);

     insert(y,x,0);

   end;

  for i:=1 to n do begin insert(0,i,1);insert(i,0,0);end;

  for i:=1 to n do begin insert(i,n+1,1);insert(n+1,i,0);end;

  while bfs do maxflow:=maxflow+dfs(0,INF);

  write(maxflow);

end.

 

  

你可能感兴趣的:(《啊哈!算法》第8章详解)