1. 程式人生 > >二分圖最大匹配(HK)

二分圖最大匹配(HK)

二分圖最大匹配經典的演算法就是匈牙利演算法,但是本文並不是講述匈牙利演算法,而是說一個時間複雜度更為優的HK演算法。
先定義x方點,y方點為二分圖中不同的兩方點。
實現過程:
1.將所有x方點中未蓋點全部加入佇列。
2.進行廣搜,找出短小的可增廣路。
具體過程如下:

    1>每次進行訪問時,找到y方點中沒有標號的點,將它的標號設為x方點的標號+1。
    2>如果所選的y方點是未蓋點,則找到了“可增廣路”,不繼續搜尋這條線。
    3>如果所選的y方點時匹配點,則沿著那條路繼續搜。同時將其匹配的x方點的標號設為y方點標號+1.

3,找到未蓋點,匈牙利演算法搜尋,尋找增廣路,但是訪問的點必須時前一個點的標號+1。

程式碼:
其中dx為x方點的標號,dy為y方點的標號,linkx為x方點的匹配點,linky為y方點的匹配點。

/*
written by tyx_yali
2017.02.09
*/
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define For(aa,bb,cc) for(int aa=bb;aa<=cc;++aa)
#define Set(aa,bb) memset(aa,bb,sizeof(aa))
using namespace std; const int maxn=250010; int n,m,s,ans; int be[maxn],ne[maxn],to[maxn],e; int linkx[maxn],linky[maxn]; int dx[maxn],dy[maxn]; void add(int x,int y){ to[++e]=y,ne[e]=be[x],be[x]=e; if(!linkx[x] && !linky[y]) linkx[linky[y]=x]=y,++ans; } bool bfs(){ bool flag=0; int
q[maxn],f=0,l=0; Set(dx,0),Set(dy,0); For(i,1,n){ if(!linkx[i]) q[++l]=i; } while(f<l){ int k=q[++f]; for(int i=be[k];i;i=ne[i]){ int u=to[i]; if(!dy[u]){ dy[u]=dx[k]+1; if(!linky[u]) flag=1; else dx[linky[u]]=dy[u]+1,q[++l]=linky[u]; } } } return flag; } bool dfs(int node){ for(int i=be[node];i;i=ne[i]){ int u=to[i]; if(dy[u]==dx[node]+1){ dy[u]=0; if(!linky[u] || dfs(linky[u])){ linkx[linky[u]=node]=u; return 1; } } } return 0; } void work(){ scanf("%d%d%d",&n,&m,&s); For(i,1,s){ int x,y; scanf("%d%d",&x,&y); add(x,y); } while(bfs()){ For(i,1,n){ if(!linkx[i] && dfs(i)) ++ans; } } printf("%d\n",ans); For(i,1,n){ printf("%d ",linkx[i]); } puts(""); } int main(){ work(); return 0; }