二分图总结

大佬总结

通俗有趣的讲解

二分图判定(染色法)

poj 2492

#include<cstdio>
#include<cstring>
#define REP(i, a, b) for(register int i = (a); i < (b); i++)
#define _for(i, a, b) for(register int i = (a); i <= (b); i++)
using namespace std;

const int MAXN = 2000 + 10;
const int MAXM = 1e6 + 10;
struct Edge { int to, next; };
Edge edges[MAXM << 1];
int head[MAXN], vis[MAXN];
int color[MAXN],  n, m, num = 0;

void addEdge(int from, int to)
{
	edges[num] = Edge{to, head[from]};
	head[from] = num++;
}

bool dfs(int u)
{
	vis[u] = 1;
	for(int i = head[u]; ~i; i = edges[i].next)
	{
		int v = edges[i].to;
		if(vis[v])
		{
			if(color[u] == color[v]) return false;
		}
		else
		{
			color[v] = color[u] ^ 1;
			if(!dfs(v)) return false;
		}
	}
	return true;
}

bool judge()
{
	_for(i, 1, n)
		if(!vis[i])
		{
			color[i] = 0;
			if(!dfs(i)) return false;
		}
	return true;
}

int main()
{
	int T;
	scanf("%d", &T);
	
	_for(kase, 1, T)
	{
		memset(head, -1, sizeof(head));
		memset(vis, 0, sizeof(vis));
		memset(color, 0, sizeof(color));
		num = 0;
		
		scanf("%d%d", &n, &m);
		while(m--)
		{
			int u, v;
			scanf("%d%d", &u, &v);
			addEdge(u, v); addEdge(v, u); 
		}
		
		printf("Scenario #%d:
", kase);
		if(!judge()) puts("Suspicious bugs found!
");
		else puts("No suspicious bugs found!
");
	}
	
	return 0;
}

二分图最大匹配 ——匈牙利算法

最小覆盖点集 = 最大匹配

poj 3041

把矩阵上的点转化成边。点(x,y)即把x和y连一条边。

最后答案即是最小覆盖点集,又知最小覆盖点集 = 最大匹配

所以敲一遍模板就好了

#include<cstdio>
#include<cstring>
#define REP(i, a, b) for(register int i = (a); i < (b); i++)
#define _for(i, a, b) for(register int i = (a); i <= (b); i++)
using namespace std;

const int MAXN = 500 + 10;
const int MAXM = 1e4 + 10;
struct Edge
{
	int to, next;
}e[MAXM];
int vis[MAXN], head[MAXN];
int link[MAXN], n, m, num, ans;

void AddEdge(int from, int to)
{
	e[num] = Edge{to, head[from]}; 
	head[from] = num++;
}

bool find(int u)
{
	for(int i = head[u]; ~i; i = e[i].next)
	{
		int v = e[i].to;
		if(vis[v]) continue;
		vis[v] = 1;
		if(!link[v] || find(link[v]))
		{
			link[v] = u;
			return true;
		}
	}
	return false;
}

int main()
{
	memset(head, -1, sizeof(head)); num = 0;
	memset(link, 0, sizeof(link));
	scanf("%d%d", &n, &m);
	
	while(m--)
	{
		int u, v;
		scanf("%d%d", &u, &v);
		AddEdge(u, v);
	}
		
	_for(i, 1, n)
	{
		memset(vis, 0, sizeof(vis));
		if(find(i)) ans++;
	}
	printf("%d
", ans);
	
	return 0;
}

poj 1274

裸题。二分图的题目要注意点和边数组开的大小。

#include<cstdio>
#include<cstring>
#define REP(i, a, b) for(register int i = (a); i < (b); i++)
#define _for(i, a, b) for(register int i = (a); i <= (b); i++)
using namespace std;

const int MAXN = 200 + 10;
const int MAXM = 4e4 + 10;
struct Edge{ int to, next; };
Edge e[MAXM];
int head[MAXN], vis[MAXN];
int link[MAXN], n, m, num;

void AddEdge(int from, int to)
{
	e[num] = Edge{to, head[from]};
	head[from] = num++;
}

bool find(int u)
{
	for(int i = head[u]; ~i; i = e[i].next)
	{
		int v = e[i].to;
		if(vis[v]) continue;
		vis[v] = 1;
		if(!link[v] || find(link[v]))
		{
			link[v] = u;
			return true;
		}
	}
	return false;
}

int main()
{
	while(~scanf("%d%d", &n, &m))
	{
		memset(head, -1, sizeof(head));
		memset(link, 0, sizeof(link));
		num = 0;
		
		_for(v, 1, n)
		{
			int t, u; scanf("%d", &t);
			while(t--)
			{
				scanf("%d", &u);
				AddEdge(u, v); 
			}
		}
	
		int ans = 0;
		_for(i, 1, n)
		{
			memset(vis, 0, sizeof(vis));
			if(find(i)) ans++;	
		}
		printf("%d
", ans);
	}

	return 0;
}
原文地址:https://www.cnblogs.com/sugewud/p/9819313.html