有些博客上的讲解是错误的。如果我的博客讲解错误,请留言,非常感谢!
1、二分图
定义:设G=(V,E)是一个无向图,如果顶点V可分割为两个互不相交的子集(A,B),并且图中的每条边(i,j)所关联的两个顶点i和j分别属于这两个不同的顶点集(i in A,j in B),则称图G为一个二分图。
判定定理:无向图G为二分图的充要条件是,G至少有两个顶点,且其所有回路的长度均为偶数。
判断方法——交替染色法
根据定义比根据定理更好判定,只需要从第一个点u出发,将其染成颜色1,则与其所有相连的所有点v都染成颜色2,再将与v相连的所有点染成1,依次下去。如果有两个相连的点被染成相同颜色,则图G不是二分图。
2、二分图最大匹配
定义:在一个无向图中,定义一条边覆盖的点为这条边的两个端点。找到一个边集S包含最多的边,使得这个边集覆盖到的所有顶点中的每个顶点只被一条边覆盖。S的大小叫做图的最大匹配。
二分图的最大匹配的匈牙利算法:
从slove()进入find(),左边结点A,找到右边结点E,匹配成功。match[E]=A。返回true到solve主程序,ans=1。
进入find(),左边结点B,首先找到右边结点E,但是match[E]!=0,所以递归回去,调整A的匹配对象,发现只能匹配E。从而返回false到find(),寻找到右边结点F,匹配成功。match[F]=B。返回true到solve(),ans=2。
进入find(),左边结点C,首先找到右边结点F,标记vis[F]=1,但是match[F]!=0,所以递归回去,调整B的匹配对象,仍然找到E,标记vis[E]=1,再次递归回去,返回false到find(),结果A仍与E匹配,因为vis[F]=1,vis[E]=1,B跳过E,F找到G匹配,返回true到find(),C与F匹配成功,从而match[C]=F,返回true到slove(),ans=3。
后续处理左边结点D类似。
标程如下:
bool dfs(int u){
for(int j=1;j<=m;j++){//遍历右侧集合
if(map[u][j] && !vis[j]){//(u,j)相邻,且右侧结点j没有占位置
vis[j]=1;//标记右侧结点j要被u占位置,从而match[j]递归时别再来尝试匹配
if(!match[j] || dfs(match[j])){
//右侧结点j还没有被匹配,或者j对应的左侧结点可以成功匹配到别的右侧结点
match[j]=u;//右侧结点j与u匹配
return 1;
}
}
}
return 0;
}
void solve(){
for(int i=1;i<=n;i++){//遍历左侧集合
memset(vis,0,sizeof(vis));//初始化占位置标记变量数组vis
if(dfs(i))
ans++;//左侧结点i匹配成功
}
}