zoukankan      html  css  js  c++  java
  • 二分图最大匹配基本模板

    最小顶点覆盖==二分图的最大匹配
    最少路径覆盖==n—最大匹配////n为左右集合中的顶点个数
    最大点独立集 = 顶点共个数 - 匹配顶点数

    多个环的并
        例如:
    有n个国家,国家之间通过有向边相连,边有权值,
        现在让你把所有的国家都划成一个一个的圈,使得所有圈的总权值和最大。
        二分图的实质就是多个环,该题就是直接求出的二分图的最大权匹配就能求出最终结果。
        二分图的多个环的并就是二分图的最大(小)权匹配。
        所以KM求得最大匹配就是结果
    ////////
    下面给出关于二分图最大匹配的两个定理
    1:最大匹配数 + 最大独立集 = n + m
    2:二分图的最小覆盖数 = 最大匹配数
    3:最小路径覆盖 = 最大独立集
    最大独立集是指求一个二分图中最大的一个点集,该点集内的点互不相连。
    最小顶点覆盖是指 在二分图中,用最少的点,让所有的边至少和一个点有关联。
    最小路径覆盖是指一个不含圈的有向图G中,G的一个路径覆盖是一个其结点不相交的 路径集合P,图中的每一个结点仅包含于P中的某一条路径。路径可以从任意结点
    开始和结束,且长度也为任意值,包括0
    二分图的多重匹配

    二分图的多重匹配
    const int maxn = 100005;
    const int maxm = 15;
    int cap[maxm];
    int Link[maxm][maxn];
    int vLink[maxm];
    int mat[maxn][maxm];
    int vis[maxm];
    int n, m;
    bool Find(int u)
    {
        for(int i = 1; i <= m; i++)
        {
            if(!vis[i] && mat[u][i])
            {
                int v = i;
                vis[v] = 1;
                if(vLink[v] < cap[v])
                {
                    Link[v][vLink[v]++] = u;
                    return true;
                }
                for(int j = 0; j < vLink[v]; j++)
                {
                    if(Find(Link[v][j]))
                    {
                        Link[v][j] = u;
                        return true;
                    }
                }
            }
        }
        return false;
    }
    
    bool solve()
    {
        memset(Link, 0, sizeof(Link));
        memset(vLink, 0, sizeof(vLink));
        for(int i = 1; i <= n; i++)
        {
            memset(vis, 0, sizeof(vis));
            if(!Find(i)) 
                return false;
        }
        return true;
    }
    
    int main()
    {
        while(EOF != scanf("%d %d",&n, &m))
        {
            for(int i = 1; i <= n; i++)
            {
                for(int j = 1; j <= m; j++)
                {
                    scanf("%d",&mat[i][j]);
                }
            }
            for(int i = 1; i <= m; i++)
            {
                scanf("%d",&cap[i]);
            }
            if(solve()) puts("YES");
            else puts("NO");
        }
        return 0;
    }

    二分图最大匹配模板

    #include<stdio.h>
    #include<string.h>
    const int maxn = 105;
    const int INF = 1000000000;
    bool vis[maxn];     //查询右集合中的点有没有被访问过
    int link[maxn];     //link[i]表示右集合中的i点是由左集合中的哪个点连接的
    int G[maxn][maxn];     //邻接矩阵
    int x_cnt;
    int y_cnt;            //左右集合的点的个数
    bool find(int u)         //用来寻找增广路
    {
        for(int i = 1; i <= y_cnt; i++)   //遍历右集合中的每个点
        {
            if(!vis[i] && G[u][i])    //没有被访问过并且和u点有边相连
            {
                vis[i] = true;  //标记该点
                if(link[i] == -1 || find(link[i]))
                {
                    //该点是增广路的末端或者是通过这个点可以找到一条增广路
                    link[i] = u;//更新增广路   奇偶倒置
                    return true;//表示找到一条增广路
                }
            }
        }
        return false;//如果查找了右集合里的所有点还没找到通过该点出发的增广路,该点变不存在增广路
    }
    
    int solve()
    {
        int num = 0;
        memset(link, -1, sizeof(link));//初始化为-1表示  不与左集合中的任何元素有link
        for(int i = 1; i <= x_cnt; i++)  //遍历左集合
        {
            memset(vis, false, sizeof(vis));//每一次都需要清除标记
            if(find(i))
                num++;//找到一条增广路便num++
        }
        return num;
    }
    int main()
    {
        while(scanf("%d%d",&x_cnt,&y_cnt)!=EOF){
            memset(G,0,sizeof(G));
            int n;
            int x,y;
            scanf("%d",&n);
            for(int i=1;i<=n;i++)
            {scanf("%d%d",&x,&y);
            G[x][y]=1;
            }
            printf("%d
    ",solve());
        }
        return 0;
    }
  • 相关阅读:
    Vue监听器、过滤器
    Vue生命周期、计算属性
    数组去重
    ES6总结
    学习笔记--html篇(1)
    学习整理--flex布局(1)
    对块作用域与变量函数提升再添新认识
    了解使用web workers
    js中的事件循环模型与特殊的定时器
    操作系统、浏览器与js之间的一些概念与联系
  • 原文地址:https://www.cnblogs.com/13224ACMer/p/4663756.html
Copyright © 2011-2022 走看看