HDU - 2063 过山车(最大匹配数)(模板)
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 过山车(最大匹配数)(模板)的更多相关文章
- hdu 2063 过山车(匈牙利算法模板)
http://acm.hdu.edu.cn/showproblem.php?pid=2063 过山车 Time Limit: 1000/1000 MS (Java/Others) Memory ...
- hdu 2063 过山车 (最大匹配 匈牙利算法模板)
匈牙利算法是由匈牙利数学家Edmonds于1965年提出,因而得名.匈牙利算法是基于Hall定理中充分性证明的思想,它是部图匹配最常见的算法,该算法的核心就是寻找增广路径,它是一种用增广路径求二分图最 ...
- hdu 2063 过山车(模板)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2063 过山车 Time Limit: 1000/1000 MS (Java/Others) Me ...
- hdu 2063 过山车 二分匹配(匈牙利算法)
简单题hdu2063 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2063 过山车 Time Limit: 1000/1000 MS (Java/Ot ...
- [HDU] 2063 过山车(二分图最大匹配)
题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=2063 女生为X集合,男生为Y集合,求二分图最大匹配数即可. #include<cstdio> ...
- hdu 2063 过山车 (二分图,最大匹配)
过山车Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submissi ...
- HDU 2063 过山车(二分图 && 匈牙利 && 最小点覆盖)
嗯... 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2063 这是一道很经典的匈牙利问题: 把男同学看成左边点,女同学看成右边点,如果两个同学愿意同 ...
- HDU 2063 过山车 第一道最大二分匹配
http://acm.hdu.edu.cn/showproblem.php?pid=2063 题目大意: m个女生和n个男生一起做过山车,每一排必须一男一女,而每个女孩愿意和一些男生坐一起,, 你要找 ...
- HDU 2063 过山车 (匈牙利算法)
题目链接:HDU 2063 Problem Description RPG girls今天和大家一起去游乐场玩,终于可以坐上梦寐以求的过山车了.可是,过山车的每一排只有两个座位,而且还有条不成文的规矩 ...
随机推荐
- Mac 10.10 配置apache
配置php 命令行工具:http://blog.csdn.net/evane1890/article/details/38759073 自从系统从OS X Mavericks 10.9升级到OS X ...
- HDU 5421 Victor and String
Victor and String Time Limit: 1000ms Memory Limit: 262144KB This problem will be judged on HDU. Orig ...
- Light oj-1259 - Goldbach`s Conjecture
1259 - Goldbach`s Co ...
- [luoguP1227] [JSOI2008]完美的对称(sort)
传送门 排序! #include <cstdio> #include <iostream> #include <algorithm> #define N 20001 ...
- [luoguP3606] [USACO17JAN]Building a Tall Barn建谷仓(贪心 + 线段树)
传送门 把线段都读进来然后排序,先按右端点为第一关键字从小到大排序,后按左端点为第二关键字从小到大排序. 注意不能先按左端点后按右端点排序,否则会出现大包小的情况,如下: —————— ——— — ...
- [luoguP1866]滑动窗口(单调队列)
传送门 可以搞2个单调队列. 然后,然后就没有然后了. # include <iostream> # include <cstdio> # include <cstrin ...
- mappedBy的作用
mappedBy的意思就是"被映射",即mappedBy这方不用管关联关系,关联关系交给另一方处理 1.规律:凡是双向关联,mapped必设,因为根本都没必要在2个表中都存在一个外 ...
- JPA框架下使用纯粹的原生SQL
最近遇到一个需求,查询数据库中对应表的字段是动态的,项目使用的框架使用JPA+Spring Boot,JPA自带原生SQL支持的传入参数是强类型的,无法用于查询语句的字段更改,因为插入字符串的话带有单 ...
- C#.net获取存储过程的Return返回值和Output输出参数值
原文发布时间为:2008-10-25 -- 来源于本人的百度文章 [由搬家工具导入] 1.获取Return返回值 程序代码//存储过程//Create PROCEDURE MYSQL// @a ...
- Gym 215177D 母亲节的礼物
Gym 215177D 母亲节的礼物 Problem : 给n个点m条边的无向图,每个点的度数小于等于7,要求用4种不同的颜色给每个点染色,使得每个点相邻的点中最多只有一个相同颜色的点.(n<= ...