带权二分图匹配:KM算法与费用流建模

KM似乎还是有点难以理解,看了半天资料仍有半懂不懂的感觉,或许以后多想想、画画,做些题能加深理解吧,当初学匈牙利的时候就是这样。

相关资料

二分图带权匹配 KM算法与费用流模型建立

丘比特的问题——求二分图最大权匹配的算法

nocow上的讲解

题目:ural1076

原题:http://acm.timus.ru/problem.aspx?space=1&num=1076

译题:http://www.nocow.cn/index.php/Translate:URAL/1076

题解:http://www.nocow.cn/index.php/URAL/1076

我的KM是抄nocow上的题解的,只不过出于习惯改了一个变量名。费用流的思路也是按nocow上的,计算出i种箱子装j种垃圾的费用然后求最小费用。根据自己的理解按照KM上的统计所有垃圾量-最大费用的程序也写了一个,不过陷入死循环中,有时间再调试吧。

我的ural1076 KM算法程序

const

  oo=199305080;

  maxn=200;

var

  lx,ly,link:array[0..maxn] of longint;

  w:array[0..maxn,0..maxn] of longint;

  i,j,k,m,n,d,tot:longint;

  x,y:array[0..maxn] of boolean;





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

begin

  if a<b then exit(B) else exit(a);

end;



procedure init;

begin

  readln(n);

  for i:=1 to n do

    for j:=1 to n do

    begin

      read(w[i,j]);

      inc(tot,w[i,j]);

    end;

end;



function dfs(v:longint):boolean;

var

  i:longint;

begin

  if v=0 then exit(true);

  x[v]:=true;

  for i:=1 to n do

    if (y[i]=false) and (lx[v]+ly[i]=w[v,i]) then

    begin

      y[i]:=true;

      if dfs(link[i]) then

      begin

        link[i]:=v;

        exit(true);

      end

    end;

  exit(false);

end;



procedure main;

begin

  for i:=1 to n do

    for j:=1 to n do

      lx[i]:=max(lx[i],w[i,j]);

  for k:=1 to n do

    while true do

    begin

      fillchar(x,sizeof(x),0);

      fillchar(y,sizeof(y),0);

      if dfs(k) then break;

      d:=oo;

      for i:=1 to n do

        if x[i] then

          for j:=1 to n do

            if (not y[j]) and (lx[i]+ly[j]-w[i,j]<d) then

               d:=lx[i]+ly[j]-w[i,j];

      for i:=1 to n do

      begin

        if x[i] then dec(lx[i],d);

        if y[i] then inc(ly[i],d);

      end

    end;

end;



procedure print;

begin

  for i:=1 to n do

    dec(tot,w[link[i],i]);

  writeln(tot);

end;



begin

  init;

  main;

  print;

end.





来一个费用流:
const

  maxn=400;

  oo=199305080;

var

  c,cost,w:array[0..maxn,0..maxn] of longint;

  flow,i,j,k,m,n,mincost,tot,s,t,pre,now,sum:longint;

  path:array[0..maxn] of longint;

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

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

function spfa:boolean;

var

  i,j,k,head,tail:longint;

begin

  head:=0;

  tail:=1;

  q[1]:=s;

  fillchar(flag,sizeof(flag),0);

  flag[s]:=true;

  for i:=1 to tot do

    dist[i]:=oo;

  dist[s]:=0;

  while head<tail do

  begin

    inc(head);

    i:=q[head];

    flag[i]:=false;

    for j:=1 to tot do

    begin

      if (c[i,j]>0) and (dist[j]>dist[i]+cost[i,j]) then

      begin

        dist[j]:=dist[i]+cost[i,j];

        path[j]:=i;

        if not flag[j] then

        begin

          flag[j]:=true;

          inc(tail);

          q[tail]:=j;

        end;

      end;

    end;

  end;

  exit(dist[t]<>oo);

end;







procedure init;

begin

  readln(n);

  for i:=1 to n do

  begin

    sum:=0;

    for j:=1 to n do

    begin

      read(w[i,n+j]);

      inc(sum,w[i,n+j]);

    end;

    for j:=1 to n do

    begin

      cost[i,n+j]:=sum-w[i,n+j];

      cost[n+j,i]:=-cost[i,n+j];

      c[i,n+j]:=1;

    end;

  end;

  s:=n*2+1;

  t:=n*2+2;

  tot:=t;

  for i:=1 to n do

    c[s,i]:=1;

  for i:=1 to n do

    c[n+i,t]:=1;

end;



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

begin

  if a<b then exit(a) else exit(b);

end;



procedure main;

begin

  while spfa do

  begin

    now:=t;

    flow:=oo;

    while now<>s do

    begin

      pre:=path[now];

      flow:=min(flow,c[pre,now]);

      now:=pre;

    end;

    now:=t;

    while now<>s do

    begin

      pre:=path[now];

      dec(c[pre,now],flow);

      inc(c[now,pre],flow);

      inc(mincost,flow*cost[pre,now]);

      now:=pre;

    end;

  end;

end;





procedure print;

begin

  writeln(mincost);

end;





begin



  init;

  main;

  print;

end.



你可能感兴趣的:(二分图)