您的位置:首页 > 其它

二分图

2015-04-25 22:47 162 查看
设G=(V,E)是一个无向图,如果顶点V可分割为两个互不相交的子集(A,B),并且图中的每条边(i,j)所关联的两个顶点i和j分别属于这两个不同的顶点集(i in A,j in B),则称图G为一个二分图。

二分图判定:

BFS就可以,一边搜一边给点上色,遇到相邻的点。如果没上色,则给它上不同的颜色,并且加入队列。如果有颜色了,判断跟现在的点颜色是否一样,一样则说明不是二分图。

例题:http://blog.csdn.net/youthinkwu/article/details/43898767

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

先来说说几个概念:

匹配:G为二分图的边集的子集,且任意两条边都没有相同的顶点,称该子边集为一个匹配。

最大匹配:边数最多的匹配称为最大匹配。

完美匹配: 如果所有点都在匹配边上,称这个最大匹配是完美匹配。

最小覆盖: 假如选了一个点就相当于覆盖了以它为端点的所有边,你需要选择最少的点来覆盖所有的边。可以证明:最少的点(即覆盖数)=最大匹配数(我并不会证明)。

最大独立集问题:

在N个点的图G中选出m个点,使这m个点两两之间没有边.求m最大值.

如果图G满足二分图条件,则可以用二分图匹配来做.最大独立集点数 = 总点数 - 最小覆盖集 = N - 最大匹配数

最小路径覆盖:

用尽量少的不相交简单路径覆盖有向无环图G的所有结点。解决此类问题可以建立一个二分图模型。把所有顶点i拆成两个:X结点集中的i和Y结点集中的i’,如果有边i->j,则在二分图中引入边i->j’,设二分图最大匹配为m,则结果就是n-m。

交错轨(路):是图的一条简单路径,满足任意相邻的两条边,一条在匹配内,一条不在匹配内。

增广轨(路):是一个始点与终点都为未匹配点的交错轨。

二分图最大匹配问题的匈牙利算法: 枚举左边点,不断寻找增广(轨)路,有增广(轨)路就说明还能增加一条边,一直寻找到再也找不到增广(轨)路为止,求出的就是最大匹配。

时间复杂度:左边点N,右边点M,边数E;

邻接表 O(NE)

邻接矩阵 O(MN^2)

最大匹配:(邻接矩阵写法)

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
const int maxn = 300;
int g[maxn][maxn],match[maxn],n,m//g邻接矩阵,match[i] = j 表示右边的点i跟左边的点j匹配,n是左边点的个数,m是右边点的个数;
bool vis[maxn];
using namespace std;
bool DFS(int u)//寻找增广(轨)路
{
for(int i = 1; i <= m; i++)
{
if(g[u][i] && !vis[i])
{
vis[i] = 1;
if(match[i] == -1 || DFS(match[i]))
{
match[i] = u;
return true;
}
}
}
return false;
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
memset(g,0,sizeof(g));
memset(match,-1,sizeof(match));
for(int i = 1; i <= n; i++)
{
int t;
scanf("%d",&t);
while(t--)
{
int u;
scanf("%d",&u);
g[u][i] = 1;//单向边就可以。
}
}
int ans = 0;
for(int i = 1; i <= n; i++)//求最大匹配。
{
memset(vis,0,sizeof(vis));
if(DFS(i)) ans ++;
}
printf("%d\n",ans);
}
return 0;
}


上面那种是能明确分出左右两边点的,有些题目是很难划分两边点的,直接对一个集合求最大匹配,那么匹配出来的ans是答案的两倍,需要除以2.

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
const int maxn = 300;
int g[maxn][maxn],match[maxn],n //g邻接矩阵,match[i] = j 表示点i跟点j匹配,n是点的总个数;
bool vis[maxn];
using namespace std;
bool DFS(int u)//寻找增广(轨)路
{
for(int i = 1; i <= n; i++)//这里是n不是m了。
{
if(g[u][i] && !vis[i])
{
vis[i] = 1;
if(match[i] == -1 || DFS(match[i]))
{
match[i] = u;
return true;
}
}
}
return false;
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
memset(g,0,sizeof(g));
memset(match,-1,sizeof(match));
for(int i = 1; i <= n; i++)
{
int t;
scanf("%d",&t);
while(t--)
{
int u;
scanf("%d",&u);
g[u][i] = 1;
g[i][u]/这里需要双向边。
}
}
int ans = 0;
for(int i = 1; i <= n; i++)//求最大匹配。
{
memset(vis,0,sizeof(vis));
if(DFS(i)) ans ++;
}
printf("%d\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息