过山车(HDU 2063)---最大匹配数

题目链接

题目描述

RPG girls今天和大家一起去游乐场玩,终于可以坐上梦寐以求的过山车了。可是,过山车的每一排只有两个座位,而且还有条不成文的规矩,就是每个女生必须找个个男生做partner和她同坐。但是,每个女孩都有各自的想法,举个例子把,Rabbit只愿意和XHD或PQK做partner,Grass只愿意和linle或LL做partner,PrincessSnow愿意和水域浪子或伪酷儿做partner。考虑到经费问题,boss刘决定只让找到partner的人去坐过山车,其他的人,嘿嘿,就站在下面看着吧。聪明的Acmer,你可以帮忙算算最多有多少对组合可以坐上过山车吗?

输入格式

输入数据的第一行是三个整数K , M , N,分别表示可能的组合数目,女生的人数,男生的人数。0<K<=1000
1<=N 和M<=500.接下来的K行,每行有两个数,分别表示女生Ai愿意和男生Bj做partner。最后一个0结束输入。

输出格式

对于每组数据,输出一个整数,表示可以坐上过山车的最多组合数。

输入样例

6 3 3
1 1
1 2
1 3
2 1
2 3
3 1
0

输出样例

3

分析

思路:将女生作为左点集(编号1~n),男生作为右点集(n+1 ~n+m)进行配对,套用匈牙利算法计算最大匹配数即可,以下分别是DFS版本和BFS版本的源代码。

源程序

DFS版本

#include <bits/stdc++.h>
#define MAXN 1005
#define MAXM 1005
using namespace std;
struct Edge{
	int u,v,next;
	Edge(){}
	Edge(int u,int v,int next):u(u),v(v),next(next){}
}edge[MAXM];
int EdgeCount,head[MAXN];
int k,n,m,link[MAXN];
bool vis[MAXN];
void addEdge(int u,int v)
{
	edge[++EdgeCount]=Edge(u,v,head[u]);
	head[u]=EdgeCount;
}
bool dfs(int u)
{
	for(int i=head[u];i;i=edge[i].next){
		int v=edge[i].v;
		if(!vis[v]){	//不在交替路中
			vis[v]=true;
			if(link[v]==-1 || dfs(link[v])){	//未匹配点或找到新方案 
				link[v]=u;
				return true;
			} 
		}
	}
	return false;
}
int hargarian()
{
	memset(link,-1,sizeof(link));
	int ans=0;	//记录匹配数 
	for(int i=1;i<=n;i++){	
		memset(vis,false,sizeof(vis));
		if(dfs(i))
			ans++; 
	}
	return ans;
}
int main()
{
	while(scanf("%d",&k)&&k){
		memset(head,0,sizeof(head));	//初始化 
		EdgeCount=0;
		scanf("%d%d",&n,&m);
		for(int i=1;i<=k;i++){	//建图
			int u,v;
			scanf("%d%d",&u,&v);
			addEdge(u,v+n);		//女生编号为1~n 
		} 						//男生编号为n+1~n+m 
		printf("%d\n",hargarian()); 
	}
}

BFS版本

#include <bits/stdc++.h>
#define MAXN 1005
#define MAXM 1005
using namespace std;
struct Edge{
	int u,v,next;
	Edge(){}
	Edge(int u,int v,int next):u(u),v(v),next(next){}
}edge[MAXM];
int EdgeCount,head[MAXN];
int k,n,m,pre[MAXN],link[MAXN],vis[MAXN];
queue<int> q;
void addEdge(int u,int v)
{
	edge[++EdgeCount]=Edge(u,v,head[u]);
	head[u]=EdgeCount;	
} 
int hargarian()
{
	memset(pre,-1,sizeof(pre));
	memset(vis,-1,sizeof(vis));
	memset(link,-1,sizeof(link));
	int ans=0;	//记录匹配数
	for(int i=1;i<=n;i++){
		if(link[i]==-1){	//尚未匹配 
			while(!q.empty()) q.pop();	//清空队列
			q.push(i);
			bool flag=false;
			while(!q.empty()&&!flag){ //寻找匹配方案 
				int u=q.front();q.pop();
				for(int j=head[u];j;j=edge[j].next){
					if(flag) break;	//已找到匹配方案
					int v=edge[j].v;
					if(vis[v]!=i){	//不在交替路中
						vis[v]=i;
						if(link[v]>=0)	//对应点已匹配
							q.push(link[v]),pre[link[v]]=u;
						else{	//找到匹配点 
							flag=true;
							int l=u,r=v;
							while(l!=-1){	//分配匹配方案
								int tmp=link[l];
								link[l]=r;
								link[r]=l;
								l=pre[l];
								r=tmp; 
							}
						} 
					} 
				}
			} 
			if(link[i]!=-1)	//该点有匹配
				ans++; 
		}
	} 
	return ans;
}
int main()
{
	while(scanf("%d",&k)&&k){
		memset(head,0,sizeof(head));	//初始化 
		EdgeCount=0;
		scanf("%d%d",&n,&m);
		for(int i=1;i<=k;i++){	//建图
			int u,v;
			scanf("%d%d",&u,&v);
			addEdge(u,n+v);	//女生编号为1~n 
		} 					//男生编号为n+1~n+m
		printf("%d\n",hargarian()); 
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值