标签:info 一个 for string sizeof href 编号 更改 lan
首先给定二分图定义
图中两个点集e1和e2
然后又一些无向边
u---v
其中u属于e1,v属于e2
匹配是指e1中一点u与e2中一点v相连则可以构成一个匹配
最大匹配是每个点仅属于一个匹配的情况下的最多匹配数
匹配边指的是已经用于匹配的边
增广路
经过一条非匹配边一条匹配边一条非匹配边一条匹配边.........一条非匹配边
然后把边的身份反转,就可以使总匹配数+1
例如图中假设一开始2-5,3-6 为非匹配边
3-5为匹配边
它们就可以构成一个增广路
只要对于属于左边点集的每个点都做一次增广路,就能得到最大匹配
解释代码中的具体执行1...n属于点集1,n+1....n+m属于点集2
建边是建单向边,从点集1的点到点集2的点
pp[i]表示已经与点集二的点的已有匹配编号,如果尚无匹配则为0
vis[i]表示对点集1的点有没有加入这次的增广中
dfs返回值表示这次增广是否成功
之后对i=1...n每个点增广
先将vis清0
然后进入dfs,增广如果成功也要将pp[i]进行更改
#include<cstdio> #include<cstring> const int N=2005; struct E{ int v,n; }e[N*N]; int s,fir[N],pp[N],vis[N]; void add(int u,int v){ e[++s].v=v; e[s].n=fir[u]; fir[u]=s; } bool dfs(int u){ for(int i=fir[u];i;i=e[i].n) if(!vis[e[i].v]){ vis[e[i].v]=1; if(!pp[e[i].v]||dfs(pp[e[i].v])) return (pp[e[i].v]=u); } return 0; } int main(){ int n,m,mm,u,v,ans=0; scanf("%d%d%d",&n,&m,&mm); while(mm--){ scanf("%d%d",&u,&v); if(u<=n&&v<=m) add(u,v+n); } for(int i=1;i<=n;++i){ memset(vis,0,sizeof(vis)); if(dfs(i)) ++ans; } printf("%d",ans); return 0; }
标签:info 一个 for string sizeof href 编号 更改 lan
原文地址:https://www.cnblogs.com/bzmd/p/10685880.html