二分图匹配--绿色算法

匈牙利人神奇的算法
          ——钟长者

最近听zhx讲课,领悟了许多人生哲理,以及各种各样清奇的脑回路。

二分图匹配算法

二分图

二分图又称作二部图,是图论中的一种特殊模型。 设G=(V,E)是一个无向图,如果顶点V可分割为两个互不相交的子集(A,B),并且图中的每条边(i,j)所关联的两个顶点i和j分别属于这两个不同的顶点集(i in A,j in B),则称图G为一个二分图。
(描述来自于简单直白的度娘)

换句话说 就是能用黑白两点把整个图染色且使相连的点颜色不同的图。

树就是一种二分图,奇层偶层分别在两边。

二分图匹配

给定一个二分图G,在G的一个子图M中,M的边集{E}中的任意两条边都不依附于同一个顶点,则称M是一个匹配。
                (又是一个简单直白的解释)
继续换句话说 给每个黑点匹配一个白点。

百度说这个问题能用最大流或匈牙利算法解决,毕竟网络流只接触过一点点,只会匈牙利算法…..

匈牙利算法原理

具体实现

STEP1
二分图匹配--绿色算法_第1张图片

STEP2
二分图匹配--绿色算法_第2张图片

STEP3
二分图匹配--绿色算法_第3张图片

这样匹配就完成了

现在来说第二种情况

假如B让A换点,但A没有别的点可换了,这种情况怎么办呢。

STEP1
二分图匹配--绿色算法_第4张图片
STEP2
二分图匹配--绿色算法_第5张图片
STEP3
二分图匹配--绿色算法_第6张图片
STEP4
二分图匹配--绿色算法_第7张图片

至此两种情况都能解决了

那为什么叫他绿色算法呢,你不觉得这个过程…
二分图匹配--绿色算法_第8张图片

复杂度分析

是用DFS来实现的,但是与暴力的DFS比起来就是快到飞起。
HDU上的dalao竟然有不用内存的,我也不知道是什么玄学算法

时间复杂度 邻接矩阵:n 邻接表:这里写图片描述

空间复杂度 邻接矩阵:这里写图片描述 邻接表: 这里写图片描述

代码实现

#include
#include
const int MAX=1001;
int n,m,k;
int link[MAX];
bool vis[MAX];
bool map[MAX][MAX];
bool dfs(int a)
{
    for(int i=1;i<=m;i++)
        if(map[a][i]==1&&!vis[i])
        {
            vis[i]=1;
            if(!link[i]||dfs(link[i]))
            {
                link[i]=a;
                return 1;
            }
        }
    return 0;
}
int main()
{
    int a,b,ans=0;
    scanf("%d%d%d",&n,&m,&k);
    for(int i=1;i<=k;i++)
    {
        scanf("%d%d",&a,&b);
        if(a>m||b>m) continue;
        map[a][b]=1;
    }
    for(int i=1;i<=n;i++)
    {
        memset(vis,0,sizeof(vis));
        if(dfs(i))
            ans++;
    }
    printf("%d\n",ans);
    return 0;
}
var
 match:array[0..1001]of longint;//子集B中元素是否被匹配
 used:array[0..1001]of boolean;//子集B中元素所对应的子集A元素
 a:array[0..1001,0..1001]of boolean; //邻接矩阵存边
 i,j,k,n,m,l,ans,t:longint;

function found(x:longint):boolean;  //找增广路
var
 i,j:longint;
begin
 for i:=1 to m do
  if (a[x,i])and(not used[i]) then
   begin
    used[i]:=TRUE;
    if (match[i]=0)or(found(i)) then  //点i未匹配,或者匹配了但是能引出另一条增广路径
     begin
      match[i]:=x;
      exit(TRUE);
     end;
   end;
 exit(FALSE);
end;

begin
 readln(n,m,t);
 for i:=1 to n do
  for j:=1 to m do
   a[i,j]:=FALSE;
 for i:=1 to t do
  begin
   readln(j,k);
   if (j>n)or(k>m) then continue; //应对坑人的数据
   a[j,k]:=TRUE;
  end;
 ans:=0;
 fillchar(match,sizeof(match),0);
 for i:=1 to n do
  begin
   fillchar(used,sizeof(used),FALSE);  //每次都要清零
   if found(i) then ans:=ans+1;  //找到增广路径匹配数加1
  end;
 writeln(ans);
end.

pascal版是我不要脸考皮的题解~不要打我。代码作者:洛谷 Antonio

钟长者说NOIP会考二分图匹配2333

二分图匹配问题 HDU 2063
二分匹配模板 luogu 3386

后续还(可能)会更新网络流,,,

你可能感兴趣的:(NOIP,算法,算法)