Algorithm --> 二分图最大匹配
匈牙利算法
二分图:把一个图的顶点划分为两个不相交集 U 和 V ,使得每一条边都分别连接U 、 V 中的顶点。如果存在这样的划分,则此图为一个二分图。

匹配:在图论中,一个「匹配」(matching)是一个边的集合,其中任意两条边都没有公共顶点。例如,图 3、图 4 中红色的边就是图 2 的匹配。

匹配点、匹配边、未匹配点、非匹配边:例如图 3 中 1、4、5、7 为匹配点,其他顶点为未匹配点;1-5、4-7为匹配边,其他边为非匹配边。
最大匹配:一个图所有匹配中,所含匹配边数最多的匹配,称为这个图的最大匹配。图4 是一个最大匹配,它包含 4 条匹配边。
完美匹配:如果一个图的某个匹配中,所有的顶点都是匹配点,那么它就是一个完美匹配。图4 是一个完美匹配。显然,完美匹配一定是最大匹配(完美匹配的任何一个点都已经匹配,添加一条新的匹配边一定会与已有的匹配边冲突)。但并非每个图都存在完美匹配。
交替路:从一个未匹配点出发,依次经过非匹配边、匹配边、非匹配边...形成的路径叫交替路。
增广路:从一个未匹配点出发,走交替路,如果途径另一个未匹配点(出发的点不算),则这条交替路称为增广路(agumenting path)。例如,图 5 中的一条增广路如图 6 所示(图中的匹配点均用红色标出):


代码:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std; const int MaxN=; int N,M;
int Ans;
int link[MaxN];
bool cover[MaxN];
bool Map[MaxN][MaxN]; void init()
{
int i,x,y;
scanf("%d%d",&N,&M);
memset(Map,false,sizeof(Map));
for(i=;i<=M;++i)
{
scanf("%d%d",&x,&y);
Map[x][y]=true;
}
}
bool Find(int i)
{
int j;
for(j=;j<=N;++j)
if(Map[i][j] && !cover[j])
{
cover[j]=true;
if(!link[j] || Find(link[j]))
{
link[j]=i;
return true;
}
}
return false;
}
void solve()
{
int i;
memset(link,,sizeof(link));
for(i=;i<=N;++i)
{
memset(cover,false,sizeof(cover));
Find(i);
}
}
void print()
{
int i;
Ans=;
for(i=;i<=N;++i)
if(link[i])
Ans++;
printf("%d\n",Ans);
for(i=;i<=N;++i)
if(link[i])
printf("%d %d\n",link[i],i);
}
int main()
{
init();
solve();
print();
return ;
}
例一:二分图
给定一个图(可能为非联通图),将其二分,得到两个数组,输出其中某个数组的个数和顶点?
输入用例(二分图检测):
算法代码:
#include <stdlib.h>
#include <stdio.h>
#include <string.h> #define MAX 1001 int path[MAX][MAX] = {};
int c[MAX] = {};
int group[MAX] = {};
int count = ;
int N, E;
int value[] = {, , };
int partition(int start) //给每个点分组,存到group[]
{
for(int i = ; i < c[start]; i++)
{
int city = path[start][i];
if(group[city] != )
{
if(group[city] == group[start])return ; //相邻两个点分组一样,则返回0,不是二分图
}
else
{
group[city] = value[group[start]];
if (group[city] == )count++;
if(!partition(city))return ;
}
} return ;
} int getNoGroup(int * pt)
{
for (int i = ; i <= N; i++)
{
if (!group[i])
{
*pt = i;
return ;
}
} return ;
} int main(void)
{
freopen("input3.txt", "r", stdin);
//freopen("output.txt", "w", stdout); for(int test_case = ; test_case <= ; test_case++)
{
scanf("%d %d\n", &N, &E);
for(int i = ; i < E; i++)
{
int pt1, pt2;
scanf("%d %d", &pt1, &pt2);
path[pt1][c[pt1]++] = pt2;
path[pt2][c[pt2]++] = pt1;
} int start = ;
bool errorFlag = false; //判断是否是二分图
while(getNoGroup(&start)) //当非连通图的时候,也能遍历到
{
group[start] = ;
if(!partition(start))
{
errorFlag = true;
break;
}
} if(errorFlag)printf("#%d -1\n", test_case);
else
{
printf("#%d %d", test_case, count);
for(int i = ; i <= N; i++)if(group[i] == )printf(" %d", i);
printf("\n");
} memset(group, , MAX*);
memset(path, , MAX*MAX*);
} return ;
}
例二:圣诞礼物
给定人数和礼物数量,接下来给出每个人喜欢的礼物的编号,求最大匹配?
输入用例(二分图最大匹配):
算法代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <vector>
using namespace std; #define MAX 401 int map[MAX][MAX] = { }; //第i个人的每个礼物的编号
int c[MAX] = { }; //第i个人一共可能连多少个礼物
int check[MAX] = { }; //表示当前第i个人已经遍历过的礼物编号
int matching[MAX] = { }; //礼物和人匹配的状态 bool dfs(int u)
{
for (int i = ; i < c[u]; i++)
{
int v = map[u][i];
if (!check[v])
{
check[v] = true;
if(matching[v] == || dfs(matching[v]))
{
matching[v] = u;
matching[u] = v;
return true;
}
}
}
return false;
} int main(int argc, char** argv)
{
freopen("input.txt", "r", stdin);
int case_max;
scanf("%d\n", &case_max);
for(int case_num = ; case_num < case_max; case_num++)
{
int personCnt, giftCnt;
scanf("%d %d\n", &personCnt, &giftCnt);
for(int i = ; i <= personCnt; i++)
{
int favoriteCnt;
scanf("%d ", &favoriteCnt);
for(int j = ; j <= favoriteCnt; j++)
{
int favorite;
scanf("%d", &favorite);
//map[i].push_back(personCnt+favorite);
map[i][c[i]++] = personCnt + favorite;
map[personCnt + favorite][c[personCnt + favorite]++] = i;
}
} int result = ;
for(int i = ; i <= personCnt; i++)
{
if (matching[i] == )
{
memset(check, , sizeof(check));
if(dfs(i))result++;
}
} printf("%d\n", result); memset(map, , sizeof(int)*MAX*MAX);
}
}
Algorithm --> 二分图最大匹配的更多相关文章
- POJ2239 Selecting Courses(二分图最大匹配)
题目链接 N节课,每节课在一个星期中的某一节,求最多能选几节课 好吧,想了半天没想出来,最后看了题解是二分图最大匹配,好弱 建图: 每节课 与 时间有一条边 #include <iostream ...
- UESTC 919 SOUND OF DESTINY --二分图最大匹配+匈牙利算法
二分图最大匹配的匈牙利算法模板题. 由题目易知,需求二分图的最大匹配数,采取匈牙利算法,并采用邻接表来存储边,用邻接矩阵会超时,因为邻接表复杂度O(nm),而邻接矩阵最坏情况下复杂度可达O(n^3). ...
- POJ3057 Evacuation(二分图最大匹配)
人作X部:把门按时间拆点,作Y部:如果某人能在某个时间到达某门则连边.就是个二分图最大匹配. 时间可以二分枚举,或者直接从1枚举时间然后加新边在原来的基础上进行增广. 谨记:时间是个不可忽视的维度. ...
- ZOJ1654 Place the Robots(二分图最大匹配)
最大匹配也叫最大边独立集,就是无向图中能取出两两不相邻的边的最大集合. 二分图最大匹配可以用最大流来解. 如果题目没有墙,那就是一道经典的二分图最大匹配问题: 把地图上的行和列分别作为点的X部和Y部, ...
- HDU:过山车(二分图最大匹配)
http://acm.hdu.edu.cn/showproblem.php?pid=2063 题意:有m个男,n个女,和 k 条边,求有多少对男女可以搭配. 思路:裸的二分图最大匹配,匈牙利算法. 枚 ...
- UOJ #78 二分图最大匹配
#78. 二分图最大匹配 从前一个和谐的班级,有 nl 个是男生,有 nr 个是女生.编号分别为 1,…,nl 和 1,…,nr. 有若干个这样的条件:第 v 个男生和第 u 个女生愿意结为配偶. 请 ...
- 【网络流#6】POJ 3041 Asteroids 二分图最大匹配 - 《挑战程序设计竞赛》例题
学习网络流中ing...作为初学者练习是不可少的~~~构图方法因为书上很详细了,所以就简单说一说 把光束作为图的顶点,小行星当做连接顶点的边,建图,由于 最小顶点覆盖 等于 二分图最大匹配 ,因此求二 ...
- [HDU] 2063 过山车(二分图最大匹配)
题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=2063 女生为X集合,男生为Y集合,求二分图最大匹配数即可. #include<cstdio> ...
- [POJ] 1274 The Perfect Stall(二分图最大匹配)
题目地址:http://poj.org/problem?id=1274 把每个奶牛ci向它喜欢的畜栏vi连边建图.那么求最大安排数就变成求二分图最大匹配数. #include<cstdio> ...
随机推荐
- SAS︱操作语句(if、do、select、retain、array)、宏语言、统计量、运算符号
每每以为攀得众山小,可.每每又切实来到起点,大牛们,缓缓脚步来俺笔记葩分享一下吧,please~ --------------------------- SAS中的一些常见的符号.运算符是一种符号①比 ...
- java代码调用使用cxf搭建的webService服务传递对象
前边成功创建好一个cxf的webServcie服务,并带了一个无参数的方法.现在进一步尝试了使用带参数的方法,分别测了用String为参数和用自定义的对象为参数. 其中,使用String为参数时和不带 ...
- 【linux】 vsftpd自动
开机默认VSFTP服务自动启动: 方法一-常用方便的方法 [root@localhost /]# chkconfig --list|grep vsftpd vsftpd 0:off ...
- 百度地图JavaScript API经纬度查询-MAP
百度地图JavaScript API经纬度查询-MAP-ABCDEFGHIJKMHNOPQRSTUVWXYZ: 搜索:<input type="text" size=&quo ...
- 提取DirectShow中视频采集的数据
DirectShow中,数据流(Data Flow)都是依次流过各个Filter的.它对数据的管理也有自己的方法,而且并没有向用户提供一个统一的接口,供用户操作数据流.这里以提取视频采集在的每帧为位图 ...
- DirectX:函数可以连接任意两个filter
函数可以连接任意两个filter HRESULT ConnectFilters( IBaseFilter *pSrc, IBaseFilter *pDest ) { IPin *pIn = 0; IP ...
- boost asio allocation
allocation演示了自定义异步操作的内存分配策略,因为asio在执行异步IO操作时会使用系统函数来动态分配内存,使用完后便立即释放掉:在IO操作密集的应用中,这种内存动态分配策略会较大地影响程序 ...
- 原根求解算法 && NTT算法
原根求解算法: 获取一个数\(N\)的原根\(root\)的算法 #include<bits/stdc++.h> #define ll long long #define IL inlin ...
- [BZOJ1083] [SCOI2005] 繁忙的都市 (kruskal)
Description 城市C是一个非常繁忙的大都市,城市中的道路十分的拥挤,于是市长决定对其中的道路进行改造.城市C的道路是这样分布的:城市中有n个交叉路口,有些交叉路口之间有道路相连,两个交叉路口 ...
- 构造方法里的super()方法
为什么经常会遇到有的构造函数会有super(),而有的却没有,其实super就比如 对数函数,log的底数为10,如果为10 ,我们可写可不写,如果不为10,那么我们就要加上底数 在子类构造方法中,s ...