二分图

二分图

定义

二分图,又称二部图,英文名叫 Bipartite graph。

二分图是什么?节点由两个集合组成,且两个集合内部没有边的图。

换言之,存在一种方案,将节点划分成满足以上性质的两个集合。

二分图的性质:二分图一定不存在长度为奇数的环

染色法判定是否为二分图

思路分析:我们可以对每个点进行DFS并进行染色,如果存在一条边的两点颜色相同则说明不是二分图。

代码示例:

//#pragma comment(linker,   "/STACK:10240000000000,10240000000000")
//#pragma GCC optimize(2)

#include <bits/stdc++.h>
using namespace std;

#define For(i,a,b) for (int i=(a);i<=(b);++i)
#define Fod(i,b,a) for (int i=(b);i>=(a);--i)
#define mls multiset
#define lb lower_bound
#define ub upper_bound
#define pb push_back
#define pob pop_back
#define itt iterator
#define endl '\n'
#define IOS ios::sync_with_stdio(0); cin.tie(0);
#define lowbit(x) x & (-x)
#define clr(x) memset(x, 0, sizeof(x));
#define fi first
#define se second

typedef vector<int> vii;
typedef vector<long long> vll;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
		
const int MAXN = 0x7fffffff;
const int MOD = 1000000007;
const ll MOD1 = 212370440130137957ll;

const int N = 1e5 + 5;
int h[N], e[2 * N], ne[2 * N], idx;
int color[N];
int n, m;

void add(int a, int b)
{
	e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}

bool dfs(int u, int c)
{
	color[u] = c;
	for(int i = h[u]; i != -1; i = ne[i]) //对点u的每条出边进行染色
	{
		int j = e[i];
		if(!color[j]) //如果还没有染色
		{
			if(!dfs(j, 3 - c)) return false; //如果染色失败
		}
		else if(color[j] == c) return false; //如果两点颜色相同
	}
	return true;
}

int main ()
{	
	//IOS;
	cin >> n >> m;
	memset(h, -1, sizeof h);

	for(int i = 1; i <= m; i ++)
	{
		int a, b;
		cin >> a >> b;
		add(a, b);
		add(b, a);
	}

	bool flag = true;

	for(int i = 1; i <= n; i ++)
		if(!color[i])
			if(!dfs(i, 1)) //dfs(i, c)表示对i进行dfs染色后是否成功
			{
				flag  = false;
				break;
			}
	if(flag) puts("Yes");
	else puts("No");

	return 0;
}	

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

我们先将点归为两个集合,分别记为1和2

由于要找到最大匹配,我们只需对1进行遍历向2匹配即可,不用对2再进行一遍同样操作。对于每一个点,我们先遍历他的所有出边,随后只要找到一个能匹配的就进行匹配,并用数组记录下来,但如果出边的终点已经有匹配了,则就再去寻找出边终点匹配的点(已用数组记录)是否有其他可匹配的点

代码示例:

//#pragma comment(linker,   "/STACK:10240000000000,10240000000000")
//#pragma GCC optimize(2)

#include <bits/stdc++.h>
using namespace std;

#define For(i,a,b) for (int i=(a);i<=(b);++i)
#define Fod(i,b,a) for (int i=(b);i>=(a);--i)
#define mls multiset
#define lb lower_bound
#define ub upper_bound
#define pb push_back
#define pob pop_back
#define itt iterator
#define endl '\n'
#define IOS ios::sync_with_stdio(0); cin.tie(0);
#define lowbit(x) x & (-x)
#define clr(x) memset(x, 0, sizeof(x));
#define fi first
#define se second

typedef vector<int> vii;
typedef vector<long long> vll;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
		
const int MAXN = 0x7fffffff;
const int MOD = 1000000007;
const ll MOD1 = 212370440130137957ll;

const int N = 505;
const int M = 1e5 + 5;

int n1, n2, m;
int h[N], ne[M], e[M], idx;
int match[N];
bool st[N];

void add(int a, int b)
{
	e[idx] = b, ne[idx] = h[a], h[a] = idx ++;
}

bool find(int x)
{
	for(int i = h[x]; ~i; i = ne[i])
	{
		int j = e[i];
		if(st[j]) continue;//j这一轮已经匹配了
		st[j] = true;
		if(match[j] == 0 || find(match[j])) //match[j]存的是当前j的匹配对象
		{
			match[j] = x; //进行匹配
			return true;
		}	
	}
	return false;
}

int main ()
{	
	//IOS;
	cin >> n1 >> n2 >> m;
	memset(h, -1, sizeof h);
	for(int i = 1; i <= m; i ++)
	{
		int a, b;
		cin >> a >> b;
		add(a, b);
	}
	int res = 0;
	for(int i = 1; i <= n1; i ++)
	{
		memset(st, false, sizeof st); //每次都要初始化st,因为每一轮遍历都有可能推翻之前的匹配
		if(find(i)) res ++;
	}
	cout << res << endl;	

	return 0;
}	
posted @ 2021-11-23 23:20  Yra  阅读(187)  评论(0)    收藏  举报