浏览器标题切换
浏览器标题切换end
把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

二分图染色及最大匹配(匈牙利算法)略解

二分图定义

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

二分图染色

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

二分图最大匹配

匈牙利算法,复杂度\(O(nm)\),实际上一般跑不满。
算法流程的话见网上blog如:这篇博客
细节上的话,一部分向另一部分连边即可不用连双向,代码中多一个\(dfn\)数组主要是为了避免多次重复访问导致\(TLE\)或爆栈,\(dfn\not = 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('\n')
#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);
} 
posted @ 2019-07-27 13:03  henry_y  阅读(264)  评论(0编辑  收藏  举报