1、男生女生一起坐过山车,每一排有两个座位,但是有个条件,就是每个女生必须找个男生做同伴一起(但是女生只愿意和某几个男生中的一个做同伴),求最多可以有多少对男女生组合坐上过山车。

2、二分图的最大匹配,女生作为X集合(左边),男生作为Y集合(右边)

3、

3.1匈牙利算法(邻接矩阵):

/*
顶点编号从0开始的
邻接矩阵(匈牙利算法)
二分图匹配(匈牙利算法的DFS实现)(邻接矩阵形式)
初始化:g[][]两边顶点的划分情况
建立g[i][j]表示i->j的有向边就可以了,是左边向右边的匹配
g没有边相连则初始化为0
uN是匹配左边的顶点数,vN是匹配右边的顶点数
左边是X集,右边是Y集
调用:res=hungary();输出最大匹配数
优点:适用于稠密图,DFS找增广路,实现简洁易于理解
时间复杂度:O(VE)
*/
#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std; const int MAXN=;
int uN,vN;//u,v 的数目,使用前面必须赋值
int g[MAXN][MAXN];//邻接矩阵,记得初始化
int linker[MAXN];//linker[v]=u,表示v(右边Y集合中的点)连接到u(左边X集合中的点)
bool used[MAXN];
bool dfs(int u){//判断以X集合中的节点u为起点的增广路径是否存在
for(int v=;v<vN;v++)//枚举右边Y集合中的点
if(g[u][v]&&!used[v]){//搜索Y集合中所有与u相连的未访问点v
used[v]=true;//访问节点v
if(linker[v]==-||dfs(linker[v])){//是否存在增广路径
//若v是未盖点(linker[v]==-1表示没有与v相连的点,即v是未盖点),找到增广路径
//或者存在从与v相连的匹配点linker[v]出发的增广路径
linker[v]=u;//设定(u,v)为匹配边,v连接到u
return true;//返回找到增广路径
}
}
return false;
}
int hungary(){//返回最大匹配数(即最多的匹配边的条数)
int res=;//最大匹配数
memset(linker,-,sizeof(linker));//匹配边集初始化为空
for(int u=;u<uN;u++){//找X集合中的点的增广路
memset(used,false,sizeof(used));//设Y集合中的所有节点的未访问标志
if(dfs(u))res++;//找到增广路,匹配数(即匹配边的条数)+1
}
return res;
} int main(){
int i,ans;
int K,M,N;//K边数,M是左边的顶点数,N是右边的顶点数
int u,v;
while(~scanf("%d",&K)){
if(K==)break;
scanf("%d%d",&M,&N);
uN=M;//匹配左边的顶点数
vN=N;//匹配右边的顶点数
memset(g,,sizeof(g));//二分图的邻接矩阵初始化
for(i=;i<K;++i){
scanf("%d%d",&u,&v);
g[--u][--v]=;//顶点编号从0开始的
}
ans=hungary();
printf("%d\n",ans);
}
return ;
}

3.2匈牙利算法(邻接表):

/*
//顶点编号从0开始的
匈牙利算法邻接表形式
使用前用init()进行初始化,给uN赋值
加边使用函数addedge(u,v)
*/
#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std; const int MAXN=;//点数的最大值
const int MAXM=;//边数的最大值
struct Edge{
int to,next;
}edge[MAXM];
int head[MAXN],tot;
void init(){
tot=;
memset(head,-,sizeof(head));
}
void addedge(int u,int v){
edge[tot].to=v;
edge[tot].next=head[u];
head[u]=tot++;
}
int linker[MAXN];
bool used[MAXN];
int uN;
bool dfs(int u){
for(int i=head[u];i!=-;i=edge[i].next){
int v=edge[i].to;
if(!used[v]){
used[v]=true;
if(linker[v]==-||dfs(linker[v])){
linker[v]=u;
return true;
}
}
}
return false;
}
int hungary(){
int res=;
memset(linker,-,sizeof(linker));
//点的编号0~uN-1
for(int u=;u<uN;u++){
memset(used,false,sizeof(used));
if(dfs(u))res++;
}
return res;
}
int main(){
int i,ans;
int K,M,N;
int u,v;
while(~scanf("%d",&K)){
if(K==)break;
scanf("%d%d",&M,&N);
uN=M;//匹配左边的顶点数
init();//初始化
for(i=;i<K;++i){
scanf("%d%d",&u,&v);
addedge(--u,--v);//顶点编号从0开始的
}
ans=hungary();
printf("%d\n",ans);
}
return ;
}

3.3匈牙利算法(邻接表,用vector实现):

/*
//顶点编号从1开始的
用STL中的vector建立邻接表实现匈牙利算法
效率比较高
处理点比较多的效率很高。1500的点都没有问题
*/
#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<vector>
using namespace std; const int MAXN=;//这个值要超过两边个数的较大者,因为有linker
int linker[MAXN];
bool used[MAXN];
vector<int>G[MAXN];
int uN;
bool dfs(int u)
{
int sz=G[u].size();
for(int i=; i<sz; i++)
{
if(!used[G[u][i]])
{
used[G[u][i]]=true;
if(linker[G[u][i]]==-||dfs(linker[G[u][i]]))
{
linker[G[u][i]]=u;
return true;
}
}
}
return false;
} int hungary()
{
int u;
int res=;
memset(linker,-,sizeof(linker));
for(u=; u<=uN; u++)
{
memset(used,false,sizeof(used));
if(dfs(u)) res++;
}
return res;
} int main()
{
int i,ans;
int K,M,N;
int u,v;
while(~scanf("%d",&K))
{
if(K==)break;
scanf("%d%d",&M,&N);
uN=M;//匹配左边的顶点数
for(i=; i<MAXN; i++)//二分图的邻接表初始化
G[i].clear();
for(i=; i<K; ++i)
{
scanf("%d%d",&u,&v);
G[u].push_back(v);//顶点编号从1开始的
}
ans=hungary();
printf("%d\n",ans);
}
return ;
}

3.4Hopcroft-Karp算法(邻接矩阵):

/* *********************************************
//顶点编号从1开始的
二分图匹配(Hopcroft-Carp的算法)。
初始化:g[][]邻接矩阵
调用:res=MaxMatch(); Nx,Ny要初始化!!!
时间复杂大为 O(V^0.5 E)
适用于数据较大的二分匹配
需要queue头文件
********************************************** */
#include<iostream>
#include<stdio.h>
#include<queue>
#include<string.h>
using namespace std;
const int MAXN=;
const int INF=<<;
int g[MAXN][MAXN],Mx[MAXN],My[MAXN],Nx,Ny;
int dx[MAXN],dy[MAXN],dis;
bool vst[MAXN];
bool searchP()
{
queue<int>Q;
dis=INF;
memset(dx,-,sizeof(dx));
memset(dy,-,sizeof(dy));
for(int i=; i<=Nx; i++)
if(Mx[i]==-)
{
Q.push(i);
dx[i]=;
}
while(!Q.empty())
{
int u=Q.front();
Q.pop();
if(dx[u]>dis) break;
for(int v=; v<=Ny; v++)
if(g[u][v]&&dy[v]==-)
{
dy[v]=dx[u]+;
if(My[v]==-) dis=dy[v];
else
{
dx[My[v]]=dy[v]+;
Q.push(My[v]);
}
}
}
return dis!=INF;
}
bool DFS(int u)
{
for(int v=; v<=Ny; v++)
if(!vst[v]&&g[u][v]&&dy[v]==dx[u]+)
{
vst[v]=;
if(My[v]!=-&&dy[v]==dis) continue;
if(My[v]==-||DFS(My[v]))
{
My[v]=u;
Mx[u]=v;
return ;
}
}
return ;
}
int MaxMatch()
{
int res=;
memset(Mx,-,sizeof(Mx));
memset(My,-,sizeof(My));
while(searchP())
{
memset(vst,,sizeof(vst));
for(int i=; i<=Nx; i++)
if(Mx[i]==-&&DFS(i)) res++;
}
return res;
} int main()
{
int i,ans;
int K,M,N;
int u,v;
while(~scanf("%d",&K))
{
if(K==)break;
scanf("%d%d",&M,&N);
Nx=M;//匹配左边的顶点数
Ny=N;//匹配右边的顶点数
memset(g,,sizeof(g));//二分图的邻接矩阵初始化
for(i=; i<K; ++i)
{
scanf("%d%d",&u,&v);
g[u][v]=;//顶点编号从1开始的
}
ans=MaxMatch();
printf("%d\n",ans);
}
return ;
}

3.5Hopcroft-Karp算法(邻接表,用vector实现):

/*
//顶点编号从0开始的
二分图匹配(Hopcroft-Karp算法)
复杂度O(squt(n)*E)
邻接表存图,vector实现
vector先初始化,然后加入边
uN为左端的顶点数,使用前赋值(点编号0开始)
*/
#include<iostream>
#include<stdio.h>
#include<vector>
#include<queue>
#include<string.h>
using namespace std; const int MAXN=;
const int INF=0x3f3f3f3f;
vector<int>G[MAXN];
int uN;
int Mx[MAXN],My[MAXN];
int dx[MAXN],dy[MAXN];
int dis;
bool used[MAXN];
bool SearchP(){
queue<int>Q;
dis=INF;
memset(dx,-,sizeof(dx));
memset(dy,-,sizeof(dy));
for(int i=;i<uN;i++)
if(Mx[i]==-){
Q.push(i);
dx[i]=;
}
while(!Q.empty()){
int u=Q.front();
Q.pop();
if(dx[u]>dis)break;
int sz=G[u].size();
for(int i=;i<sz;i++){
int v=G[u][i];
if(dy[v]==-){
dy[v]=dx[u]+;
if(My[v]==-)dis=dy[v];
else{
dx[My[v]]=dy[v]+;
Q.push(My[v]);
}
}
}
}
return dis!=INF;
}
bool DFS(int u){
int sz=G[u].size();
for(int i=;i<sz;i++){
int v=G[u][i];
if(!used[v]&&dy[v]==dx[u]+){
used[v]=true;
if(My[v]!=-&&dy[v]==dis)continue;
if(My[v]==-||DFS(My[v])){
My[v]=u;
Mx[u]=v;
return true;
}
}
}
return false;
}
int MaxMatch(){
int res=;
memset(Mx,-,sizeof(Mx));
memset(My,-,sizeof(My));
while(SearchP()){
memset(used,false,sizeof(used));
for(int i=;i<uN;i++)
if(Mx[i]==-&&DFS(i))
res++;
}
return res;
} int main(){
int i,ans;
int K,M,N;
int u,v;
while(~scanf("%d",&K)){
if(K==)break;
scanf("%d%d",&M,&N);
uN=M;//匹配左边的顶点数
for(i=;i<MAXN;++i)//二分图的邻接表初始化
G[i].clear();
for(i=;i<K;++i){
scanf("%d%d",&u,&v);
G[--u].push_back(--v);//顶点编号从0开始的
}
ans=MaxMatch();
printf("%d\n",ans);
}
return ;
}

HDU - 2063 过山车(最大匹配数)(模板)的更多相关文章

  1. hdu 2063 过山车(匈牙利算法模板)

    http://acm.hdu.edu.cn/showproblem.php?pid=2063 过山车 Time Limit: 1000/1000 MS (Java/Others)    Memory ...

  2. hdu 2063 过山车 (最大匹配 匈牙利算法模板)

    匈牙利算法是由匈牙利数学家Edmonds于1965年提出,因而得名.匈牙利算法是基于Hall定理中充分性证明的思想,它是部图匹配最常见的算法,该算法的核心就是寻找增广路径,它是一种用增广路径求二分图最 ...

  3. hdu 2063 过山车(模板)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2063 过山车 Time Limit: 1000/1000 MS (Java/Others)    Me ...

  4. hdu 2063 过山车 二分匹配(匈牙利算法)

    简单题hdu2063 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2063 过山车 Time Limit: 1000/1000 MS (Java/Ot ...

  5. [HDU] 2063 过山车(二分图最大匹配)

    题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=2063 女生为X集合,男生为Y集合,求二分图最大匹配数即可. #include<cstdio> ...

  6. hdu 2063 过山车 (二分图,最大匹配)

    过山车Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submissi ...

  7. HDU 2063 过山车(二分图 && 匈牙利 && 最小点覆盖)

    嗯... 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2063 这是一道很经典的匈牙利问题: 把男同学看成左边点,女同学看成右边点,如果两个同学愿意同 ...

  8. HDU 2063 过山车 第一道最大二分匹配

    http://acm.hdu.edu.cn/showproblem.php?pid=2063 题目大意: m个女生和n个男生一起做过山车,每一排必须一男一女,而每个女孩愿意和一些男生坐一起,, 你要找 ...

  9. HDU 2063 过山车 (匈牙利算法)

    题目链接:HDU 2063 Problem Description RPG girls今天和大家一起去游乐场玩,终于可以坐上梦寐以求的过山车了.可是,过山车的每一排只有两个座位,而且还有条不成文的规矩 ...

随机推荐

  1. STM32F407 独立看门狗 个人笔记

    什么是看门狗 如果程序跑飞了怎么办? 可以用看门狗来监控. 看门狗是: 一个递减的计数器,如果不按时给计数器赋值,计数器的值减到一定程度,就会使系统复位. 也就是说如果程序运行异常,无法正常给计数器赋 ...

  2. URI跟URL的区别

    关于URL和URI的区别,个人见解.    初学java,最近被一个概念搞得头晕脑胀,就是url和uri的概念和区别,网上查了一大通,发现各种回答眼花缭乱,有百科直接粘贴的,有胡说八道的,有故意绕来绕 ...

  3. 如何设置目标并发(或者目标RPS)?

    基本概念 首先您需要了解什么是并发用户.TPS 和它们之间的关系. 并发用户:指的是现实系统中同时操作业务的用户,在性能测试工具中一般称为虚拟用户(Virutal User).一般是站在客户侧评估的角 ...

  4. B/S 开发和 C/S开发的区别

    导读:每天都从应用中心下载很多软件安装尝试,在自己的电脑上也装了很多软件,但是,就出现了一个问题,好比QQ,为什么有了APP,还要有网站应用呢?由此,结合到自己的学习,就衍生出一个问题:C/S 开发就 ...

  5. BZOJ3027 - [CEOI2004]Sweet

    Portal Description 给出\(n(n\leq10),a,b(a,b\leq10^7)\)与\(\{c_n\}(c_i\leq10^6)\),求使得\(\sum_{i=1}^n x_i ...

  6. CCF 201712-4 90分

    90分,不知道错在哪里了,dijkstra算法,用一个数组的d[i]表示以i点结尾的小路的长度,以i点为中心扩展时,若下一点为k,如果i->k是小路,则 d[j] = d[k]+M[k][j]; ...

  7. [转]GitHub 优秀的 Android 开源项目

    GitHub 优秀的 Android 开源项目 主要介绍那些不错个性化的View,包括ListView.ActionBar.Menu.ViewPager.Gallery.GridView.ImageV ...

  8. BZOJ1696: [Usaco2007 Feb]Building A New Barn新牛舍

    n<=10000个点(xi,yi),找到一个不同于给出的所有点的点,使得该点到所有点的曼哈顿距离最小并找出这样的点的个数. 第一眼看上去这不是中位数嘛,奇数一个点偶数一片,然后找一下这篇区域有几 ...

  9. 【转载】在Javascript中 声明时用"var"与不用"var"的区别

    原文链接:http://www.2cto.com/kf/201204/128406.html[侵删]   Javascript声明变量的时候,虽然用var关键字声明和不用关键字声明,很多时候运行并没有 ...

  10. Python()-类命名空间和对象/实例命名空间

    类命名空间和对象/实例命名空间: 创建类, 就会创建一个类的名称空间, 空间:存储类的属性 属性: 静态属性:直接定义在类下面 & 和类名关联 的变量 对象属性:在类内和self关联 & ...