二分图匹配

来源:互联网 发布:php 发送xml格式报文 编辑:程序博客网 时间:2024/05/17 22:35

二分图最大匹配

匈牙利算法

核心思想

找到增广路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

0 0