二分图简介
二分图是一种图论模型,其特点在于可以将图内的点分进两个集合,而每个集合内部的点没有直接关联,常用的二分图模型有二分图匹配
二分图最大匹配
1. 几种实现方法
代码原题
1. 匈牙利算法
1 #include2 using namespace std; 3 typedef long long LL; 4 const int INF=1e9+7,MAXN=1e3+1,MAXM=1e6+1; 5 int N,M,E,ans; 6 int used[MAXN],match[MAXN]; 7 int head[MAXN],to[MAXM],nxt[MAXM],tp; 8 inline void add(int x,int y){ 9 nxt[++tp]=head[x];10 head[x]=tp;11 to[tp]=y;12 }13 int dfs(int x){ //x->cur vertex14 for(int i=head[x];i;i=nxt[i]){15 if(!used[to[i]]){16 used[to[i]]=1;17 if(!match[to[i]]||dfs(match[to[i]])){18 match[to[i]]=x;19 return 1;20 }21 }22 }23 return 0;24 }25 int main(){26 scanf("%d%d%d",&N,&M,&E);27 for(int i=1;i<=E;i++){28 int ii,jj;29 scanf("%d%d",&ii,&jj);30 if(ii<=N&&jj<=M){31 add(ii,jj);32 }33 }34 for(int i=1;i<=N;i++){35 memset(used,0,sizeof(used));36 if(dfs(i)){37 ans++;38 }39 }40 printf("%d",ans);41 return 0;42 }
2.最大流算法(此处是ISAP)
1 #include2 using namespace std; 3 typedef long long LL; 4 const int INF=1e9+7,MAXN=3e3+1,MAXM=2e6+1; 5 int N,M,E; 6 int head[MAXN],to[MAXM*2],nxt[MAXM*2],val[MAXM*2],tp=1; 7 inline void add(int x,int y,int z){ 8 nxt[++tp]=head[x]; 9 head[x]=tp;10 to[tp]=y;11 val[tp]=z;12 nxt[++tp]=head[y];13 head[y]=tp;14 to[tp]=x;15 }16 int S,T,de[MAXN],gap[MAXN];17 inline void bfs(){18 queue que;19 que.push(T);20 memset(de,-1,sizeof(de));21 de[T]=0;22 gap[0]=1;23 while(que.size()){24 int idx=que.front();25 que.pop();26 for(int i=head[idx];i;i=nxt[i]){27 if(-1==de[to[i]]){28 de[to[i]]=de[idx]+1;29 gap[de[to[i]]]++;30 que.push(to[i]);31 }32 }33 }34 }35 int maxflow,cur[MAXN];36 int dfs(int x,int flow){37 if(x==T){38 maxflow+=flow;39 return flow;40 }41 int used=0;42 for(int &i=cur[x];i;i=nxt[i]){43 if(val[i]&&de[to[i]]+1==de[x]){44 int ii=dfs(to[i],min(flow-used,val[i]));45 if(ii){46 val[i]-=ii;47 val[i^1]+=ii;48 used+=ii;49 if(used==flow){50 return used;51 }52 }53 }54 }55 gap[de[x]]--;56 if(!gap[de[x]]){57 de[S]=N+M+2;58 }59 de[x]++;60 gap[de[x]]++;61 return used;62 }63 inline void ISAP(){64 bfs();65 while(de[S]<=N+M+1){66 memcpy(cur,head,sizeof(cur));67 dfs(S,INF);68 }69 printf("%d",maxflow);70 }71 int main(){72 scanf("%d%d%d",&N,&M,&E);73 S=0;74 T=N+M+1;75 for(int i=1;i<=N;i++){76 add(S,i,1);77 }78 for(int i=1;i<=M;i++){79 add(i+N,T,1);80 }81 for(int i=1;i<=E;i++){82 int ii,jj;83 scanf("%d%d",&ii,&jj);84 if(ii<=N&&jj<=M){85 add(ii,jj+N,1);86 }87 }88 ISAP();89 return 0;90 }
2. 简单应用
(1) 朴素的匹配问题
这一类问题的就是将一个实际问题转化为用一些对象匹配另一些对象的问题,难点在于建模,思维难度较高。这类问题大多数可以用匈牙利算法,代码短;也可以用网络流,代码长,效率高
例题:
(利用匈牙利算法的简单性质)
(巧妙的建模)
(2) 需要输出方案的匹配问题
(匈牙利算法输出方案)
(Dinic算法)