现在的位置: 首页 > 综合 > 正文

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

2012年03月28日 ⁄ 综合 ⁄ 共 2683字 ⁄ 字号 评论关闭

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.

抱歉!评论已关闭.