二分图的最大匹配,点覆盖集,边覆盖集,最大独立集,最大团

参考

【2018五一清北培训】【2】【二分图以及匈牙利算法】
二分图最大匹配总结——kuangbin的ACM博客
关于最大匹配,最小点覆盖,最少路径覆盖和最大独立集的总结

二分图的最大匹配

  1. 二分图:对于一个图G=(V,E),若能将其点集分为两个互不相交的两个子集X、Y,使得X∩Y=∅,且对于G的边集V,若其所有边的顶点全部一侧属于X,一侧属于Y,则称图G为一个二分图。
  2. 二分图判定:无奇环,可以用黑白染色判断。
  3. 匹配: 对于一个二分图G的子图M,若M的边集E的的任意两条边都不连接同一个顶点,则称M为G的一个匹配。
  4. 最大匹配:若二分图G的一个匹配M为其边数最多的匹配,则称M为G的最大匹配。
  5. 最大匹配的求法:匈牙利算法;网络流:源点到左侧点,左侧点到右侧点,右侧点到汇点间都建流量为1的边,最大流即为最大匹配。

其它性质

  1. 最小点覆盖集:点覆盖集是指图中的一个点集,且图中所有的边都至少有一个端点在点集中。最小点覆盖集即为点数最小的点覆盖集。
  2. 最少边覆盖集:边覆盖集是指图中的一个边集,且图中所有的点都至少为边集中一条边的端点。最小边覆盖集即为边数最少的边覆盖集。
  3. 最大独立集:独立集是指图中的一个点集,且这些点之间两两无边相连。最大独立集是指点数最多的独立集。
  4. 最大团:团是指图中的一个点集,且这些点之间两两有边相连(完全图)。最大团是指点数最多的团。
  5. 公式:
    • 二分图的最小点覆盖 = 二分图的最大匹配(证明见König定理)
    • 二分图的最少边覆盖 = 点数 - 二分图的最大匹配
    • 二分图的最大独立集 = 点数 - 二分图的最大匹配
    • 无向图的最大团 = 无向图补图的最大独立集

洛谷P3386 【模板】二分图匹配

使用网络流算法,最大流用了lrj的dinic板子。

#include 
using namespace std; using ll = long long; inline int read();
const int M = 4096, INF = 0x3f3f3f3f;

//dinic.cpp DINIC算法跑最大流
struct Dinic
{
    struct Edge
    {
        int from, to, cap, flow;
    };
    int n, m, s, t; 	
    vector<Edge> edges; 
    vector<int> G[M]; 	
    bool vis[M]; 		
    int d[M]; 			
    int cur[M]; 		
    void addEdge(int from, int to, int cap)
    {
        edges.push_back(Edge({from, to, cap, 0}));
        edges.push_back(Edge({to, from, 0, 0}));
        m = edges.size();
        G[from].push_back(m - 2);
        G[to].push_back(m - 1);
    }
    bool BFS()
    {
        memset(vis, 0, sizeof(vis));
        queue<int> q;
        q.push(s);
        d[s] = 0;
        vis[s] = 1;
        while(!q.empty())
        {
            int u = q.front();
            q.pop();
            for(int id : G[u])
            {
                Edge &e = edges[id];
                if(!vis[e.to] && e.cap > e.flow)
                {
                    vis[e.to] = 1;
                    d[e.to] = d[u] + 1;
                    q.push(e.to);
                }
            }
        }
        return vis[t];
    }
    int DFS(int u, int a)
    {
        if(u == t || a == 0) return a;
        int flow = 0, f;
        for(int &i = cur[u]; i < (int)G[u].size(); ++i)
        {
            Edge &e = edges[G[u][i]];
            if(d[u] + 1 == d[e.to] && 
            	(f = DFS(e.to, min(a, e.cap - e.flow))) > 0)
            {
                e.flow += f;
                edges[G[u][i] ^ 1].flow -= f;
                flow += f;
                a -= f;
                if(a == 0) break;
            }
        }
        return flow;
    }
    int maxflow(int s, int t)
    {
        this->s = s;
        this->t = t;
        int flow = 0;
        while(BFS())
        {
            memset(cur, 0, sizeof(cur));
            flow += DFS(s,INF);
        }
        return flow;
    }
};

int main(void)
{
    Dinic dinic;
    int n = read(), m = read(), e = read();
    int s = 0, t = n+m+1;
    dinic.n = n+m;
    while(e--)
    {
        int a = read(), b = read()+n;
        if(a>n || b>n+m) continue;
        dinic.addEdge(a, b, 1);
    }
    for(int i=1;i<=n;++i)
        dinic.addEdge(s,i,1);
    for(int i=n+1;i<=n+m;++i)
        dinic.addEdge(i,t,1);
    printf("%d\n",dinic.maxflow(s,t) );
}

inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9') {if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}

你可能感兴趣的:(学习笔记)