对于一个图G(V,E),它的匹配M是二元组(u,v)组成的集合,其中u,v∈V,(u,v)∈E,并且M中不存在重复的点。
当|M|最大的时候,我们称M为G的最大匹配。
当G是一个二分图的时候,它的最大匹配可以用经典的匈牙利算法或网络流算法求解。然而当G是一个一般的图时,直接进行增广就变得不可行了,这个时候我们要用带花树算法完成匹配的任务。
1 #include<cstdio> 2 #include<cctype> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 int read() { 7 int x=0,f=1; 8 char c=getchar(); 9 for (;!isdigit(c);c=getchar()) if (c=='-') f=-1; 10 for (;isdigit(c);c=getchar()) x=x*10+c-'0'; 11 return x*f; 12 } 13 const int maxn=505; 14 const int maxm=maxn*maxn*2; 15 int n,m,que[maxm],ql,qr,pre[maxn],tim=0; 16 struct edge { 17 int v,nxt; 18 } e[maxm]; 19 int h[maxn],tot=0; 20 int match[maxn],f[maxn],tp[maxn],tic[maxn]; 21 int find(int x) { 22 return f[x]==x?f[x]:f[x]=find(f[x]); 23 } 24 void add(int u,int v) { 25 e[++tot]=(edge){v,h[u]}; 26 h[u]=tot; 27 } 28 int lca(int x,int y) { 29 for (++tim;;swap(x,y)) if (x) { 30 x=find(x); 31 if (tic[x]==tim) return x; else tic[x]=tim,x=pre[match[x]]; 32 } 33 } 34 void shrink(int x,int y,int p) { 35 while (find(x)!=p) { 36 pre[x]=y,y=match[x]; 37 if (tp[y]==2) tp[y]=1,que[++qr]=y; 38 if (find(x)==x) f[x]=p; 39 if (find(y)==y) f[y]=p; 40 x=pre[y]; 41 } 42 } 43 bool aug(int s) { 44 for (int i=1;i<=n;++i) f[i]=i; 45 memset(tp,0,sizeof tp),memset(pre,0,sizeof pre); 46 tp[que[ql=qr=1]=s]=1; // 1: type A ; 2: type B 47 int t=0; 48 while (ql<=qr) { 49 int x=que[ql++]; 50 for (int i=h[x],v=e[i].v;i;i=e[i].nxt,v=e[i].v) { 51 if (find(v)==find(x) || tp[v]==2) continue; 52 if (!tp[v]) { 53 tp[v]=2,pre[v]=x; 54 if (!match[v]) { 55 for (int now=v,last,tmp;now;now=last) { 56 last=match[tmp=pre[now]]; 57 match[now]=tmp,match[tmp]=now; 58 } 59 return true; 60 } 61 tp[match[v]]=1,que[++qr]=match[v]; 62 } else if (tp[v]==1) { 63 int l=lca(x,v); 64 shrink(x,v,l); 65 shrink(v,x,l); 66 } 67 } 68 } 69 return false; 70 } 71 int main() { 72 #ifndef ONLINE_JUDGE 73 freopen("test.in","r",stdin); 74 freopen("my.out","w",stdout); 75 #endif 76 n=read(),m=read(); 77 for (int i=1;i<=m;++i) { 78 int x=read(),y=read(); 79 add(x,y),add(y,x); 80 } 81 int ans=0; 82 for (int i=1;i<=n;++i) ans+=(!match[i] && aug(i)); 83 printf("%d ",ans); 84 for (int i=1;i<=n;++i) printf("%d ",match[i]); 85 puts(""); 86 return 0; 87 }
题目来源是UOJ79,ans是最大匹配数,match[i]表示第i个人的配偶是谁。