昨天晚上开始看二分图,到现在基本的东西学会了

我就写一下我自己的理解

 

首先什么是二分图

顾名思义就是能分成两个部分的图

要注意的是,‘分’的是点

并且这两个集合(这里我们称作X集合和Y集合)内部所有的点之间没有边相连,也就是说X集合中任何两点之间都不会有边相连, Y亦然

 

定理1:无向图G为二分图的一个冲要条件是 1、G中至少包含两个顶点  2、G中所有的回路长度都必须是偶数

 

接下来是一些概念:

匹配:设G=<V, E>为二分图,如果 M⊆E,并且 M 中没有任何两边有公共端点,则成M为G的一个匹配。【也就是说匹配的实质是一些边的集合。】

最大匹配:边数最多的匹配

完备匹配与完全匹配:若 X 中所有的顶点都是匹配 M 中的端点。则称 M 为X的完备匹配。 若M既是 X-完备匹配又是 Y-完备匹配,则称M 为 G 的完全匹配。

最小点覆盖:用尽可能少的点去覆盖所有的边【最小点覆盖集是点的集合,其个数为最小点覆盖数】

最大点独立:跟网络流中的最大点权独立集有点类似,这里指的是最大独立的个数

 

接下来是二分图的一些性质:

设无向图G有n个顶点,并且没有孤立顶点,那么,

1、点覆盖数 + 点独立数 = n

2、最小点覆盖数 = 二分图的最大匹配

3、最大点独立数 = n - 最小点覆盖数 = n - 最大匹配

 

二分图的判定:

判断一个图是不是二分图有两条1、n>= 2   2、不存在奇圈

我们可以用黑白染色的方法进行判断

 1 const int maxn = 105;
 2 
 3 int col[maxn];
 4 
 5 bool is_bi(int u) {
 6     for(int i = 0; i < G[u].size(); i++) {
 7         int v = G[u][i];
 8         if(col[v] == col[u]) return false;
 9         if(!col[v]) {
10             col[v] = 3 - col[u];
11             if(!is_bi(v)) return false;
12         }
13     }
14     return true;
15 }

 

接下来介绍一下求二分图最大匹配的匈牙利算法。

匈牙利算法的思想是这样的:如果一个图中存在增广路,那么沿着这条路增广,匹配就会加1,知道不存在增广路为止

这里的增广路是这么定义的:对于一个未匹配或已经匹配好一部分的G来说

在X集合中的未匹配点出发,依次经过未匹配边匹配边未匹配边匹配边……而终点落在Y中的一个未访问点上,那么只要将该路上的匹配边于未匹配边调换,那么新的匹配必将比原来的匹配多1,【详细见http://blog.csdn.net/xuguangsoft/article/details/7861988中的图】//如果不理解可以看刘汝佳大白书,一会动手模拟一下程序即可

下面是匈牙利算法的邻接矩阵和邻接表程序

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 using namespace std;
 5 
 6 const int maxn = 105;
 7 const int INF = 1000000000;
 8 
 9 bool vis[maxn];//查询右集合中的点有没有被访问过
10 int link[maxn];//link[i]表示右集合中的i点是由左集合中的哪个点连接的
11 int G[maxn][maxn];//邻接矩阵
12 int x_cnt; int y_cnt;//左右集合的点的个数
13 
14 bool find(int u) {//用来寻找增广路
15     for(int i = 1; i <= y_cnt; i++) {//遍历右集合中的每个点
16         if(!vis[i] && G[u][i]) {//没有被访问过并且和u点有边相连
17             vis[i] = true;//标记该点
18             if(link[i] == -1 || find(link[i])){ //该点是增广路的末端或者是通过这个点可以找到一条增广路
19                 link[i] = u;//更新增广路   奇偶倒置
20                 return true;//表示找到一条增广路
21             }
22         }
23     }
24     return false;//如果查找了右集合里的所有点还没找到通过该点出发的增广路,该点变不存在增广路
25 }
26 
27 int solve() {
28     int num = 0;
29     memset(link, -1, sizeof(link));//初始化为-1表示  不与左集合中的任何元素有link
30     for(int i = 1; i <= x_cnt; i++) {//遍历左集合
31         memset(vis, false, sizeof(vis));//每一次都需要清除标记
32         if(find(i)) num++;//找到一条增广路便num++
33     }
34     return num;
35 }
匈牙利算法--邻接矩阵

相关文章:

  • 2021-04-12
  • 2021-12-10
  • 2021-07-05
  • 2021-12-21
  • 2021-10-06
  • 2021-05-12
  • 2021-07-19
  • 2021-05-23
猜你喜欢
  • 2022-01-21
  • 2022-12-23
  • 2021-08-30
  • 2021-08-25
  • 2021-06-23
  • 2021-12-19
  • 2021-04-19
相关资源
相似解决方案