二分图定义及判断,二分图最大匹配的匈牙利算法

有些博客上的讲解是错误的。如果我的博客讲解错误,请留言,非常感谢!

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的大小叫做图的最大匹配。

二分图的最大匹配的匈牙利算法

二分图定义及判断,二分图最大匹配的匈牙利算法_第1张图片

从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匹配成功 
	}		
} 

 

你可能感兴趣的:(二分图定义及判断,二分图最大匹配的匈牙利算法)