草庐IT

二分图(Bipartite Graph)

Hacker_徐 2023-09-03 原文

一、简介

二分图の定义

        二分图又叫二部图,是图论中的一种特殊模型。

        假设S=(V,E)是一个无向图。如果顶点V可分割为两个互不相交的子集(A,B),并且图中的每条边(i,j)所关联的两个顶点i和j分别属于这两个不同的顶点集(i in A,j in B),就可以称图S为一个二分图。简单来说,就是顶点集V可分割为两个互不相交的子集,并且图中每条边依附的两个顶点都分属于这两个互不相交的子集,两个子集内的顶点不相邻。

二分图の匹配

        给定一个二分图S,在S的一个子图M中,M的边集{E}中的任意两条边都不依附于同一个顶点,则称M是一个匹配。

        极大匹配是指在当前已完成的匹配下,无法再通过增加未完成匹配的边的方式来增加匹配的边数。

        最大匹配是所有极大匹配当中边数最大的一个匹配。

        选择这样的边数最大的子集称为图的最大匹配问题。如果一个匹配中,图中的每个顶点都和图中某条边相关联,则称此匹配为完全匹配,也称作完备匹配。
        完全匹配一定是极大匹配,但是极大匹配不一定是完全匹配。下图就是一个最大匹配。

 二分图の判断

       对于二分图的判断方法最常见的是染色法,就是对每一个点进行染色操作,只用黑白两种颜色,能不能使所有的点都染上了色且相邻两个点的颜色不同?如果可以那么这个图就是一个二分图,对于判断是否是一个二分图的方法可以用dfs和bfs两种方式去实现。代码参见“代码实现”部分。

二分图の最大匹配

        给定一个二分图S,在S的一个子图M中,M的边集中的任意两条边都不依附于同一个顶点,则称M是一个匹配。选择这样的边数最大的子集称为图的最大匹配问题。

        首先要了解两个概念:

|交替路|从一个未匹配的点出发,依次经过未匹配边、匹配边、未匹配边....

|增广路|从一个未匹配的点出发,走交替路,到达了一个未匹配过的点。  

        对于求二分图最大匹配的算法可以用网络流去跑一个最大流求解,还可以用二分图的常见算法匈牙利算法,这个算法的核心就是去找未匹配的点,然后从这个点出发去寻找增广路,因为增广路有几个主要的特点:

  • 增广路有奇数条边 。
  • 路径上的点一定是一个在X边,一个在Y边,交错出现。
  • 起点和终点都是目前还没有配对的点。
  • 未匹配边的数量比匹配边的数量多1。

        重点是第4点,我们可以根据此特性,把这条增广路中的匹配边改为未匹配边,把未匹配边改为匹配边,这样我们就可以使总匹配边数+1了,根据上面的图得出下图,很显然匹配边多了一条。

        代码见“代码实现”部分。

二、代码实现

“二分图の判断”配套代码:

BFS判断二分图

vector<int>G[maxn];//存边
int col[maxn];//标记顶点颜色
int n,m;//点和边的个数
bool bfs()
{
  queue<int>q;
  q.push(1);//放入第一个点
  memset(col,0,sizeof(col));
  col[1]=1;//先标记第一个点为1
  while(!q.empty())
  {
    int v=q.front();
    q.pop();
    for(int i=0; i<G[v].size(); i++)
    {
      int xx=G[v][i];
      if(col[xx]==0)//判断这个点是否标记过
      {
        col[xx]=-col[v];//没有标记过就标记上与v相反的颜色
        q.push(xx);
      }
      else
      {
        if(col[v]==col[xx])//如果颜色冲突说明不是二分图
        {
          return false;
        }
      }
    }
  }
  return true;
}

“二分图の最大匹配”配套代码

匈牙利算法代码

vector<int> G[maxn];//存边
int pre[maxn];//记录匹配点
bool vis[maxn];//标记是否匹配过
int n,m;//n个点 m条边
bool dfs(int x)
{
  for(int i=0; i<G[x].size(); i++)
  {
    int v=G[x][i];
    if(vis[v]==false)//判断是否标记过
    {
      vis[v]=true;
      if(pre[v]==-1||dfs(pre[v]))// 判断当前点是否匹配过 dfs为判断这个点能不能和其他的点匹配
      {
        pre[v]=x;
        return true;
      }
    }
  }
  return false;
}
int Fun()
{
  int sum=0;
  memset(pre,-1,sizeof(pre));
  for(int i=1; i<=n; i++)
  {
    memset(vis,false,sizeof(vis));//每次遍历都需要初始化
    if(dfs(i)) 
    {
        sum++;
    }
  }
  return sum;
}


参考文献:

干货|二分图详解https://www.zhihu.com/tardis/landing/m/360/art/89972891以上内容就是本文的全部内容啦!感谢阅读!

有关二分图(Bipartite Graph)的更多相关文章

  1. 常见搜索模板DFS+BFS+二分搜索【算法】 - 2

     本篇讲的是常见的搜索模板,搜索题的解法时比较固定的,只要把模板记熟,加上自己找几道习题练习体会后,相信各位下次遇到这类题一定能拿下!!下面我将已典型的题目为例子介绍几种常见的搜索方式。 1.二分搜索二分搜索代码模板:例题:#includeusingnamespacestd;doublen;constdoubleeps=1e-12;//二分搜索intmain(){ intt; cin>>t; while(t--){ cin>>n; doublel=0,r=100000,res=-1; while(ln)r=mid-0.0001; elseif(mid*mid*mid二分搜索是只能对有

  2. day1-数组part01| 704. 二分查找、27. 移除元素 - 2

    数组理论基础数组是存放在连续内存空间上的相同类型数据的集合。数组下标从0开始数组内存空间的地址是连续的c++中vector和array的区别1、vector是顺序容器,其利用连续的内存空间来存储元素,但是其内存空间大小是能够改变的。2、array是顺序容器,其也是利用连续的内存空间来存储元素,但它的内存空间是固定大小的,申请之后就无法改变。3、vector的底层是array实现的二维数组二维数组在内存的空间地址是连续的704|二分查找思路1、把整个数组一分为二;2、判断目标值在左区间还是右区间,若在左区间,则修改右区间指针的位置;若在右区间,则修改新区间的左区间位置3、重复上述过程,直到lef

  3. 数学建模十大算法04—图论算法(最短路径、最小生成树、最大流问题、二分图) - 2

    文章目录一、最短路径问题1.1两个指定顶点之间的最短路径1.1.1Dijkstra算法1.1.2Matlab函数1.2每对顶点之间的最短路径1.2.1Dijkstra算法1.2.2Floyd算法1.2.3Matlab函数二、最小生成树问题2.1Kruskal算法2.2Prim算法三、网络最大流问题3.1网络流问题基础3.2Ford-Fulkerson算法3.3Edmonds-Karp算法3.4Dinic's算法3.5最小割问题(Min-Cut)3.5.1S-TCut3.5.2★最大流-最小割定理(Max-FlowMin-CutTheorem)3.5.3**寻找最小割的方法**四、二分图一、最短

  4. 代码随想录算法训练营第一天 704 二分查找、27 移除元素 - 2

    代码随想录算法Day1|704.二分查找、27.移除元素Lasteditedtime:April5,202311:27AM数据理论基础数组是存放在连续内存空间上的相同类型数据的集合。数组下标都是从0开始的。数组内存空间的地址是连续的数组元素不能删除,只能覆盖C++中二维数组的内存的空间地址是连续的704.二分查找二分法前提:数组为有序数组,且数组中无重复元素循环不变量:对区间的定义应该是一个不变量,在边界处理中应该遵循统一原则左闭右闭:classSolution{public:intsearch(vectorint>&nums,inttarget){intleft=0;intright=num

  5. 【查找算法】二分查找(C# + 递归、非递归和变种形式) - 2

    【查找算法】二分查找(C#+递归、非递归和变种形式)写在前面:本文主要介绍二分查找算法,通过图片解析每一次查找的情况。代码通过C#实现,分别有递归、非递归和变种三种形式。其中变种主要解决数组出现重复数据的问题。最后,我们还分析了二分查找的局限性。活动地址:CSDN21天学习挑战赛本文关键字:经典算法、查找算法、二分查找、图解、C#文章目录【查找算法】二分查找(C#+递归、非递归和变种形式)一、算法效率1.时间复杂度2.空间复杂度二、查找算法1.顺序(线性)查找2.二分查找/折半查找3.插值查找4.斐波那契查找三、算法实践1.图解算法原理2.算法实现非递归实现递归实现3.二分查找变种3.时间复杂

  6. 二分图(概念、相关算法和题目应用)(全面整理) - 2

    TP二分图的概念:二分图常用算法:染色法(判断一个图是否为二分图):匈牙利算法(求出二分图的最大匹配数):相应题目应用:二分图染色应用:Acwing:关押罪犯二分图最大匹配应用:Acwing:棋盘覆盖洛谷:矩阵游戏二分图最大匹配的一些推论:二分图最小点覆盖应用:Acwing:机械任务Acwing:泥地二分图最大独立集应用:Acwing:骑士放置二分图最大路径点覆盖与最大路径重复点覆盖应用:Acwing:捉迷藏二分图的概念:二分图通常针对无向图问题(有些题目虽然是有向图,但一样有二分图性质)在一张图中,如果能够把全部的点分到两个集合中,保证两个集合内部没有任何边,图中的边只存在于两个集合之间,这

  7. 新冠肺炎胸部 CT 基于3D-CNN实现二分类 - 2

    新冠肺炎胸部CT基于3D-CNN实现二分类作者:WangXi2016日期:2022.10.27摘要:本示例教程使用3DCNN实现CT数据二分类。1、介绍本示例将展示构建3D卷积神经网络(3DCNN),以预测电子计算机断层扫描(CT)是否感染新冠病毒肺炎。2DCNN通常用于处理RGB图像(3个通道)。3DCNN:它将3D数据或2D帧序列(例如CT扫描中的切片)作为输入,这个架构可以从3D深度或者连续视频帧中产生多通道的信息,然后在每一个通道都分离地进行卷积和下采样操作。最后将所有通道的信息组合起来得到最终的特征描述。2、解压数据集完整数据集链接:https://www.medrxiv.org/c

  8. java - 为什么 CompletableFuture allOf 方法会进行二分查找? - 2

    我想知道CompletableFuture的allOf方法是否进行轮询或进入等待状态,直到所有CompletableFutures都传递给该方法完成他们的执行。我查看了IntelliJ中的allOf方法的代码,它正在执行某种二进制搜索。请帮助我找出CompletableFuture的allOf方法实际上做了什么。publicstaticCompletableFutureallOf(CompletableFuture...cfs){returnandTree(cfs,0,cfs.length-1);}/**Recursivelyconstructsatreeofcompletions.*

  9. c++ - 如何找到二分查找算法的迭代次数? - 2

    如何获取二分查找的迭代次数?这是我的代码:intmain(){inttarget=11;intN=10;std::vectorindex;intnum;for(inti=0;i我想知道迭代次数取决于N。我知道这个算法是如何工作的,但我想要迭代次数用数学表示。 最佳答案 我会通过使用递归二进制搜索函数来递归递增。在二进制检查的每个分支中,只需递增1即可递归计算迭代次数。Seelivehere#include#includestd::size_tbinarySearch(conststd::vector&arr,//passarraya

  10. C++ 字符串数组二分查找 - 2

    stringHaystack[]={"Alabama","Alaska","AmericanSamoa","Arizona","Arkansas","California","Colorado","Connecticut","Delaware","DistrictofColumbia","Florida","Georgia","Guam","Hawaii","Idaho","Illinois","Indiana","Iowa","Kansas","Kentucky","Louisiana","Maine","Maryland","Massachusetts","Michigan","M

随机推荐