一、什么是二分图:
二分图又称作二部图,是图论中的一种特殊模型。 设G=(V,E)是一个无向图,如果顶点V,E 可分割为两个互不相交的子集(A,B),并且图中的每条边(i,j)所关联的两个顶点i和j分别属于这两个不同的顶点集(i in A,j in B),则称图G为一个二分图。
二、二分图的判断、二分图染色
判断方法就是染成两种颜色。
如果与相连切未染色 就把他染成异色
如果相连的已经染色 就判断是否颜色不同 (如果 颜色相同 表示不能构成二分图)
注意!!!:不连通的图(有多个连通分支的图)!
①bfs 判断:
int vis[maxn]; /*********染色标记数组******/
int bfs(int s)
{
memset(vis,0, sizeof(vis));/******/
queue<int>que;
que.push(s);
vis[s] = 1;
while(!que.empty())
{
int tp = que.front();
que.pop();
for(int i = 1;i <= M;i++)
{
if(mp[tp][i])/*****如果相连接**/
{
if(!vis[i])/***没被遍历, 就 染成 与tp 不同颜色的图*****/
{
vis[i] = vis[tp]== 1?2:1;
que.push(i);
}
else if(vis[i] == vis[tp])/*****如果与自己相邻 且颜色相同 表示不是二分图 返回1******/
return 1;
}
}
}
return 0;
}
② dfs判断:
#include <iostream>
#include <vector>
#include <cstring>
using namespace std;
const int MAX_N =105;
int V,E;
// 使用邻接表模拟一张无向图
vector<int> G[MAX_N];
// 顶点的颜色,初始化为0,上色有两种颜色(0 or 1)
int color[MAX_N];
bool dfs(int v, int c)
{
color[v] = c; // 把顶点染成c
for(int i = 0; i < G[v].size(); i++)
{
// 如果当前点的相邻的点同色就返回false
if(color[G[v][i]] == c)
return false;
// 如果当前点的邻点还没被染色,就染成-c
if(color[G[v][i]] == 0 && !dfs(G[v][i], -c))
return false;
}
// 如果当前点都被染过色,就返回true
return true;
三、匈牙利算法的关键:
①有一个可以储存所有二分图连线的数组(可以是一维,也可以是二维数组,怎么方便怎么来 )
②有一个link[]数组(名字叫 连接数组),用于标记已经链接的 二分图定点。
③就是有一个mark[] (标记数组)——作用:在拆分某个两个顶点时, 防止这两个点在连接
大牛的匈牙利算法的讲解(通俗易懂):
https://blog.csdn.net/dark_scope/article/details/8880547
三、相关题:
二分图——匈牙利算法的匹配题:
- hdu1083(二分图匹配):https://cn.vjudge.net/problem/HDU-1083
- HDU1083:https://vjudge.net/problem/HDU-2063
HDU1083 过山车题
#include<stdio.h>
#include<string.h>
int map[505][505];// i表示男 j表示女 i男和j女可以作伴 就 在i j 处标记 (即 储存 输入的信息)
int link[505];//用于标记 已经配对完成的 男女(连接函数)
int mark[505];//用于标记 该男子不能再配对的 女
int K, M, N;
int dfs(int x)
{
int j;
for(j = 1; j<= M; j++)
{
if(map[x][j] == 1&&mark[j] == 0)// 如果该男子和女子可以作伴, 并且mark为0, 就可以进行内部操作
{
mark[j] = 1;//标记
if(link[j] == 0||dfs(link[j]))//如果 该女子和别的男人已经作伴, 就拆散他们 让那个男的在找一个(因为mark 已经标记 所以那个男的不可以在找该女子)
{
link[j] = x;//现在的男子和女子作伴
return 1;//返回一表示 又有一对
}
}
}
return 0;
}
int hunger()
{
memset(link, 0,sizeof(link));//先初始化 连接函数
int res = 0, i;//res 统计最多有几对
for(i = 1; i <= N; i++)
{
memset(mark, 0,sizeof(mark));//初始化标记函数, 为0表示 在i男子若与某女子可以作伴的前提下, 该男子可以和女子连接
res+=dfs(i);//
}
return res;
}
int main ()
{
while(~scanf("%d", &K)&&K!= 0)
{
scanf("%d %d", &M, &N);
int i;
memset(map, 0, sizeof(map));
for(i = 0; i < K; i++)
{
int a,b;
scanf("%d %d", &a, &b);
map[b][a] = 1;
}
int sum = hunger();
printf("%d\n", sum);
}
return 0;
}