二分图匹配

二分图最大匹配

匈牙利算法

核心思想

找到增广路ans+1,至找不到增广
具体参照https://www.byvoid.com/blog/hungary

复杂度(以下以邻接链表来说)

时间复杂度O(VE)(V表示一侧的点数,E表示二分图的边数)
空间复杂度O(V+E)
UOJ#78. 二分图最大匹配模板测试

var
 w:array[0..400000,1..2]of longint;
 x,y,z:array[0..600]of longint;
 i,j,k:longint;
 ans,len,n1,n2,m,a,b:longint;
procedure init(a,b:longint);
begin
 w[len,1]:=b;
 if w[a,2]=0
 then w[a,2]:=len else w[w[a,1],2]:=len;
 w[a,1]:=len; inc(len);
end;

function path(a:longint):longint;
var tt:longint;
begin
 tt:=w[a,2];
 while tt<>0 do
  begin
   if y[w[tt,1]]=0
   then begin
    y[w[tt,1]]:=1;
    if (x[w[tt,1]]=0)or(path(x[w[tt,1]])=1)
    then begin x[w[tt,1]]:=a; z[a]:=w[tt,1]; exit(1); end;
   end;
   tt:=w[tt,2];
  end;
 exit(0);
end;

procedure find;
var i:longint;
begin
 for i:=1 to n1 do
  begin
   fillchar(y,sizeof(y),0);
   if path(i)=1 then inc(ans);
  end;
end;

begin
 readln(n1,n2,m); len:=n1+1;
 for i:=1 to m do
  begin
   readln(a,b);
   init(a,b);
  end;
 ans:=0; fillchar(x,sizeof(x),0);
 find;
 writeln(ans);
 for i:=1 to n1 do
  write(z[i],' ');
 writeln;
end.

二分图匹配模型

http://blog.csdn.net/acdreamers/article/details/8621130

  • (1)二分图的最小顶点覆盖
    最小顶点覆盖要求用最少的点(X或Y中都行),让每条边都至少和其中一个点关联。
    Knoig定理:二分图的最小顶点覆盖数等于二分图的最大匹配数。
    http://www.matrix67.com/blog/archives/116
    构造一组解的话,就是X中未覆盖的点和Y中已覆盖的点
  • (2)DAG图的最小路径覆盖
    用尽量少的不相交简单路径覆盖有向无环图(DAG)的所有顶点,这就是DAG图的最小路径覆盖问题。
    结论:DAG图的最小路径覆盖数 = 节点数(n)- 最大匹配数(m)
  • (3)二分图的最大点独立集
    最大独立集问题: 在N个点的图G中选出m个点,使这m个点两两之间没有边.求m最大值
    结论:二分图的最大点独立集数 = 节点数(n)— 最大匹配数(m)=DAG图的最小路径(边)覆盖数

题目

网络流24题 飞行员配对方案问题

http://cojs.tk/cogs/problem/problem.php?pid=14
题解:模板题

COGS718. [SDOI2007] 环球旅行问题

http://cojs.tk/cogs/problem/problem.php?pid=718
题解:最小路径覆盖模型

HDU1083 Courses

http://acm.hdu.edu.cn/showproblem.php?pid=1083
题目大意:判定二分图完备匹配
完备匹配:二分图两侧点集X,Y,假设|X|<|Y|,若有|X|条边将X都匹配上,则存在该二分图的完备匹配
题解:匈牙利求解最大匹配,若等于最小点集则存在完备匹配

二分图最优匹配

KM算法

  • 二分图最优匹配定义:在最大匹配下,边权(非负)和最大
    UOJ#80. 二分图最大权匹配模板测试
const
  maxn=405;
var
  w,map:array[0..maxn,0..maxn]of longint;
  x,y,xl,yl,match:array[0..maxn]of longint;
  i,j,k:longint;
  n1,n2,n,m,a,b,c,esp:longint;
  ans:int64;
function max(a,b:longint):longint;
begin if a>b then exit(a) else exit(b); end;

function min(a,b:longint):longint;
begin if a<b then exit(a) else exit(b); end;

function hungary(a:longint):longint;
var i,tt:longint;
begin
  x[a]:=1;
  for i:=1 to n do
    if (w[a,i]=xl[a]+yl[i])and(y[i]=0) then
      begin
        y[i]:=1;
        if (match[i]=0)or(hungary(match[i])=1)
        then begin match[i]:=a; exit(1); end;
      end;
  exit(0);
end;

procedure km;
var i:longint;
begin
  //xl,yl为两边的顶标
  //x,y为是否为交替边
  fillchar(xl,sizeof(xl),0);
  fillchar(yl,sizeof(yl),0);
  fillchar(match,sizeof(match),0);
  for i:=1 to n do
    begin
      xl[i]:=-maxlongint;
      yl[i]:=0;
      for j:=1 to n do
        xl[i]:=max(xl[i],w[i,j]);
    end;
  for i:=1 to n do
    while i<=n do
      begin
        fillchar(x,sizeof(x),0);
        fillchar(y,sizeof(y),0);
        if hungary(i)=1
        then break
        else
          begin
            esp:=maxlongint;
            for j:=1 to n do
              if x[j]=1
              then 
                for k:=1 to n do
                  if (y[k]=0)and(esp>xl[j]+yl[k]-w[j,k])
                  then esp:=xl[j]+yl[k]-w[j,k];
            for j:=1 to n do
              begin
                if x[j]=1 then dec(xl[j],esp);
                if y[j]=1 then inc(yl[j],esp);
              end;
          end;
      end;
end;

begin
  readln(n1,n2,m); n:=max(n1,n2);
  for i:=1 to m do
    begin
      readln(a,b,c);
      w[a,b]:=c;
    end;
  km;
  for i:=1 to n do
    ans:=ans+w[match[i],i];
  writeln(ans);
end.

题目

http://acm.hdu.edu.cn/diy/contest_show.php?cid=12698

HDU2255 奔小康赚大钱

http://acm.hdu.edu.cn/showproblem.php?pid=2255
题解:模板题

HDU1533 Going Home

http://acm.hdu.edu.cn/showproblem.php?pid=1533
题目大意:给定人和房子的位置,人到房子的花费为他们的曼哈顿距离,询问最小花费
题解:最小权匹配,把权值取相反数,KM求最大匹配,ans=-ans

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