二分匹配:二分图的一些性质

二分图又称作二部图,是图论中的一种特殊模型。 设G=(V,E)是一个无向图,如果顶点V可分割为两个互不相交的子集(A,B),并且图中的每条边(i,j)所关联的两个顶点i和j分别属于这两个不同的顶点集(i in A,j in B),则称图G为一个二分图。

1。一个二分图中的最大匹配数等于这个图中的最小点覆盖数

König定理是一个二分图中很重要的定理,它的意思是,一个二分图中的最大匹配数等于这个图中的最小点覆盖数。如果你还不知道什么是最小点覆盖,我也在这里说一下:假如选了一个点就相当于覆盖了以它为端点的所有边,你需要选择最少的点来覆盖所有的边。

 

2。最小路径覆盖=最小路径覆盖=|G|-最大匹配数  在一个N*N的有向图中,路径覆盖就是在图中找一些路经,使之覆盖了图中的所有顶点,  且任何一个顶点有且只有一条路径与之关联;(如果把这些路径中的每条路径从它的起始点走到它的终点,  那么恰好可以经过图中的每个顶点一次且仅一次);如果不考虑图中存在回路,那么每每条路径就是一个弱连通子集.

由上面可以得出:

 1.一个单独的顶点是一条路径;  2.如果存在一路径p1,p2,......pk,其中p1 为起点,pk为终点,那么在覆盖图中,顶点p1,p2,......pk不再与其它的    顶点之间存在有向边.

最小路径覆盖就是找出最小的路径条数,使之成为G的一个路径覆盖.

 路径覆盖与二分图匹配的关系:最小路径覆盖=|G|-最大匹配数;

3。二分图最大独立集=顶点数-二分图最大匹配

独立集:图中任意两个顶点都不相连的顶点集合。

 

 

二分图判定:染色判定法

直接利用题目HDU 2444 The Accomodation of Students

题意:给定n个学生,他们之间可能互相认识,首先判断能不能将这些学生分为两组,使组内学生不认识;

现想将学生两两分组,且保证每一组的学生都认识,这样分组可达到的最大组数为多大?

二分图判定+二分图最大匹配 直接看代码

#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
const int MAXN = 410;
const int MAXM = MAXN * MAXN * 2;
const int INF = 0x3f3f3f3f;
struct Edge
{
    int u,v,next;
    int w;
}edge[MAXM];
int head[MAXN],tot;

void init()
{
    tot = 0;
    memset(head,-1,sizeof(head));
}

void add_edge(int u,int v,int w)
{
    edge[tot].u = u;
    edge[tot].v = v;
    edge[tot].w = w;
    edge[tot].next = head[u];
    head[u] = tot++;
}

bool used[MAXN];
int linker[MAXN],N,M;
int color[MAXN];

bool bipartite(int u)
{
    for (int i = head[u] ; i != -1 ; i = edge[i].next)
    {
        int v = edge[i].v;
        if (color[v] == color[u]) return false;
        if (!color[v])
        {
            color[v] = 3 - color[u];
            if (!bipartite(v)) return false;
        }
    }
    return true;
}

bool dfs(int u)
{
    for (int i = head[u]; i != -1 ; i = edge[i].next)
    {
        int v = edge[i].v;
        if (!used[v])
        {
            used[v] = true;
            if (linker[v] == -1 || dfs(linker[v]))
            {
                linker[v] = u;
                return true;
            }
        }
    }
    return false;
}

int calcu()
{
    memset(linker,-1,sizeof(linker));
    int ret = 0;
    for (int i = 1 ; i <= N ; i++)
    {
        memset(used,false,sizeof(used));
        if (dfs(i)) ret++;
    }
    return ret;
}
int main()
{
    while (scanf("%d%d",&N,&M) != EOF)
    {
        init();
        memset(color,0,sizeof(color));
        for (int i = 0 ; i < M ; i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            add_edge(u,v,9797);
           // add_edge(v,u,9797);
        }
        bool flag = false;
        for (int i = 1 ; i <= N ; i++)
        {
            if (color[i] == 0)
            {
                color[i] = 1;
                if (!bipartite(i))
                {
                    flag = true;
                    break;
                }
            }
        }
        if (!flag)
        {
            printf("%d\n",calcu());
        }
        else puts("No");
    }
    return 0;
}
View Code

相关文章: