• 二分图


    二分图概念
    顶点集V可分割为两个互不相交的子集,并且图中每条边依附的两个顶点都分属于这两个互不相交的子集。
    无向图G为二分图的充分必要条件
    G至少有两个顶点,且其所有回路的长度均为偶数。
    最大匹配
    给定一个二分图G,在G的一个子图M中,M的边集中的任意两条边都不依附于同一个顶点,则称M是一个匹配.
    选择这样的边数最大的子集称为图的最大匹配问题.
    最小覆盖
    最小覆盖要求用最少的点(X集合或Y集合的都行)让每条边都至少和其中一个点关联。最小覆盖=最大匹配。
    简单路径:
    如果一条路径上的顶点除了起点和终点可以相同外,其它顶点均不相同,则称此路径为一条简单路径;起点和终点相同的简单路径称为回路(或环)。
    最小路径覆盖:
    用尽量少的不相交简单路径覆盖有向无环图G的所有结点。
    增广路(增广轨):
    若P是图G中一条连通两个未匹配顶点的路径,并且属于M的边和不属于M的边(即已匹配和待匹配的边)在P上交替出现,则称P为相对于M的一条增广路径(举例来说,有A、B集合,增广路由A中一个点通向B中一个点,再由B中这个点通向A中一个点……交替进行)。
    增广路径的性质:
    1 有奇数条边。
    2 起点在二分图的左半边,终点在右半边。
    3 路径上的点一定是一个在左半边,一个在右半边,交替出现。
    4 整条路径上没有重复的点。
    5 起点和终点都是目前还没有配对的点,而其它所有点都是已经配好对的。
    6 路径上的所有第奇数条边都不在原匹配中,所有第偶数条边都出现在原匹配中。
    7 最后,也是最重要的一条,把增广路径上的所有第奇数条边加入到原匹配中去,并把增广路径中的所有第偶数条边从原匹配中删除(这个操作称为增广路径的取反),则新的匹配数就比原匹配数增加了1个。
    匈牙利算法的基本模式:
    1、 初始时最大匹配为空
    2、 while (找得到增广路径)
    3、 do 把增广路径加入到最大匹配中。
    二分图匹配中较为重要的三个公式:
    二分图最小顶点覆盖 = 二分图最大匹配;
    DAG图的最小路径覆盖 = 节点数(n)- 最大匹配数;
    二分图最大独立集 = 节点数(n)- 最大匹配数;

    样例:

    /*
    输入:第一行n,m,k,代表左子集有n个点,编号1~n,右子集有m个点,编号1~m,左右子集之间有k个关系。
    然后有n行,每行有两个数a,b。表示a,b之间相连。
    求二分图的最大匹配。
    */
    #include<iostream>
    #include<stdio.h>
    #include<string.h>
    using namespace std;
    int map[101][101];
    int link[101]; //匹配结果中右子集的点的前驱,比如说link[5]=3,
                  //代表右子集的5节点的前驱是左子集的3节点。
    int vis[101];//标记右子集的节点在找当前增广链是是否找过
    int n,m,k,s;
    int find(int x)
    {
        for(int i=1;i<=m;i++)
        {
            if(map[x][i]&&!vis[i])//当前节点在此次寻找增广链的过程中未被访问过。
            {
                vis[i]=1;
                if(link[i]==0||find(link[i]))
                //当前右节点没有前驱,或者在往前的寻找过程中找到了增广链
                {
                    link[i]=x;//如果找到了增广链,那么if成立,这条增广链上的所有右节点才会被标记前驱。
                    return 1;
                }
            }
        }
        return 0;
    }
    int main()
    {
        int a,b;
        memset(link,0,sizeof(link));
        memset(map,0,sizeof(map));
        scanf("%d%d%d",&n,&m,&k);
        for(int i=0;i<k;i++)
        {
            scanf("%d%d",&a,&b);
            map[a][b]=1;//标记图中a,b的关系
        }
        s=0;
        for(int i=1;i<=n;i++)//依次从左子集的点找增广链
        {
            memset(vis,0,sizeof(vis));
            if(find(i))s++;//存在增广链,匹配结果加1.
        }
        cout<<s<<endl;
        return 0;
    }
    


  • 相关阅读:
    Vim step by step
    Ubuntu解压命令全览
    这样才能使本地Mysql服务允许被外部主机连接(两步)
    [Python] logging.logger
    Python Selenium
    MySQL中char、varchar和text的区别
    Way to MongoDB
    Python误区之strip,lstrip,rstrip
    Android Studio Tips
    Way to tmux
  • 原文地址:https://www.cnblogs.com/jiangu66/p/3217737.html
Copyright © 2020-2023  润新知