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. 【Ajax 2】封装Ajax的核心对象:XMLHttpRequest对象

    导读:AJAX利用一个构建到所有现代浏览器内部的对象-XMLHttpRequest-来实现发送和接收HTTP请求与响应信息.那么,XMLHttpRequest对象是怎么创建和封装的呢? 一.简介 1. ...

  2. CodeForce 448C 木片填涂问题

    题目大意:有多片木片需要填涂,可以每次横着涂一行,也可以一次涂一列,当然你涂一行时遇到中间长度不够高的木片,填涂到此中断 这题目运用dfs能更容易的解出,虽然还是十分不容易理解 #include &l ...

  3. loadrunner 多用户并发操作解读

    假设存在: 数据:A.B.C 虚拟用户:Vuser1.Vuser2.Vuser3 脚本中参数出现三次,脚本迭代三次 怎样取下一行数据? Sequential:顺序,所有虚拟用户按照顺序读取数据表 Ra ...

  4. [NOIP1999] 提高组 洛谷P1016 旅行家的预算

    题目描述 一个旅行家想驾驶汽车以最少的费用从一个城市到另一个城市(假设出发时油箱是空的).给定两个城市之间的距离D1.汽车油箱的容量C(以升为单位).每升汽油能行驶的距离D2.出发点每升汽油价格P和沿 ...

  5. 【frameset】frameset设置不能拖动

    <frameset rows='20%,*' >           <!--  row 行 col 列    分行列要为rows  cols  --> <frame s ...

  6. 如何通过AS3加载外部SWF文件,调用外部文件文档类的方法?

    一个Flash中通过AS3代码的Loader对象加载另一个SWF文件,并访问其中的文档类中的方法. 简单示例: 主文件:Main.fla, Main.as 被调用的文件:called.swf, Cal ...

  7. jxls使用模版导出Excel

    /**     * 使用模版导出Excel     */    @SuppressWarnings({ "unchecked", "deprecation" } ...

  8. git批量删除本地分支及远程分支

    1.批量删除本地分支 git branch |grep 'branchName' |xargs git branch -D git branch   查看本地分支 | grep 'branchName ...

  9. Piggy-Bank--hdu1114(完全背包)

    http://acm.hdu.edu.cn/showproblem.php?pid=1114 Problem Description Before ACM can do anything, a bud ...

  10. centos、mac的grafana安装和简单使用

    1.安装: 参考官方文档安装说明:https://grafana.com/grafana/download Redhat & Centos(64 Bit): wget https://s3-u ...