zoukankan      html  css  js  c++  java
  • 二分图染色及最大匹配(匈牙利算法)略解

    二分图定义

    对于一个图G=(V,E),若能将其点集分为两个互不相交的两个子集X、Y,使得X∩Y=∅,且对于G的边集V,若其所有边的顶点全部一侧属于X,一侧属于Y,则称图G为一个二分图。

    二分图染色

    用来判定一个图是否是二分图。将点染为三种颜色(1,-1,0)(0)表示暂未染色。则对于一个颜色为(c)的点,与它相连的点都必须是(-c)这种颜色,如果在染色过程中有一条边((u,v))满足(c_u=c_v ot = 0),则该图不是二分图。

    二分图最大匹配

    匈牙利算法,复杂度(O(nm)),实际上一般跑不满。
    算法流程的话见网上blog如:这篇博客
    细节上的话,一部分向另一部分连边即可不用连双向,代码中多一个(dfn)数组主要是为了避免多次重复访问导致(TLE)或爆栈,(dfn ot = tim)则证明还未在当前该点的匹配中使用到,如果(dfn=tim)说明已经在之前尝试过了(`管是把当前点对分给了其他点还是无法匹配都对当前没有贡献了,所以不需要继续递归下去),以及在尝试增广的时候,(dfs)的是(match[v])而不是(v)

    Code

    模板题链接

    #include <bits/stdc++.h>
    using namespace std;
    
    namespace io {
    char buf[1<<21], *p1 = buf, *p2 = buf;
    inline char gc() {
        if(p1 != p2) return *p1++;
        p1 = buf;
        p2 = p1 + fread(buf, 1, 1 << 21, stdin);
        return p1 == p2 ? EOF : *p1++;
    }
    #define G gc
    
    #ifndef ONLINE_JUDGE
    #undef G
    #define G getchar
    #endif
    
    template<class I>
    inline void read(I &x) {
        x = 0; I f = 1; char c = G();
        while(c < '0' || c > '9') {if(c == '-') f = -1; c = G(); }
        while(c >= '0' && c <= '9') {x = x * 10 + c - '0'; c = G(); }
        x *= f;
    }
    
    template<class I>
    inline void write(I x) {
        if(x == 0) {putchar('0'); return;}
        I tmp = x > 0 ? x : -x;
        if(x < 0) putchar('-');
        int cnt = 0;
        while(tmp > 0) {
            buf[cnt++] = tmp % 10 + '0';
            tmp /= 10;
        }
        while(cnt > 0) putchar(buf[--cnt]);
    }
    
    #define in(x) read(x)
    #define outn(x) write(x), putchar('
    ')
    #define out(x) write(x), putchar(' ')
    
    } using namespace io;
    
    #define ll long long
    const int N = 2000100;
    
    int cnt, head[N];
    struct edge {
    	int to, nxt;
    } e[N << 1];
    int match[N], dfn[N];
    int n, m;
    
    void ins(int u, int v) {
    	e[++cnt] = (edge) {v, head[u]};
    	head[u] = cnt; 
    }
    
    bool dfs(int u, int tim) {
    	for(int i = head[u]; i; i = e[i].nxt) {
    		int v = e[i].to;
    		if(dfn[v] != tim) {
    			dfn[v] = tim;
    			if(!match[v] || dfs(match[v], tim)) {
    				match[v] = u;
    				return true;
    			}
    		}
    	}
    	return false;
    }
    
    int main() {
    	read(n); read(m);
    	int E;
    	read(E);
    	while(E--) {
    		int a, b; read(a), read(b);
    		if(a > n || b > m) continue;
    		ins(a, b + n);
    	}
    	int ans = 0;
    	for(int i = 1; i <= n; ++i) if(dfs(i, i)) ++ans;
    	outn(ans);
    } 
    
  • 相关阅读:
    【原理】【重点】异步回调的一些实现策略
    上下文传递
    洋码头全异步服务框架
    秒杀系统架构优化思路
    从urllib2的内存泄露看python的GC python引用计数 对象的引用数 循环引用
    jvisualvm All-in-One Java Troubleshooting Tool
    小心踩雷,一次Java内存泄漏排查实战
    django 请求处理流程 链路追踪
    存储过程
    Dijkstra's algorithm
  • 原文地址:https://www.cnblogs.com/henry-1202/p/11254643.html
Copyright © 2011-2022 走看看