洛谷P2055 [ZJOI2009]假期的宿舍——二分图最大匹配的匈牙利算法

题目:https://www.luogu.org/problemnew/show/P2055

关于二分图、二分图最大匹配的匈牙利算法,见我的博客:https://blog.csdn.net/qq_36314344/article/details/96274861

分析:

第一行数据,1表示本校生,0表示非本校生,这里提供了多少张床可供匹配。

第二行数据,除回家的在校生不用床铺,另外的人都要床铺。

随后的n*n矩阵,先将i==j的值改为1。从而,在矩阵(i,j)处值为1,且人员编号i需要床铺,且有床铺编号j的床,则在i到j上连边。

得到一张二分图。左边集合是需要床的人员编号,右边则是可以睡的床铺编号。

然后用匈牙利算法求出最大匹配值ans,如果ans>=需要床铺的人员数cns,则满足要求。

AC代码:

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int MaxN=55;
const int MaxM=2505;
int T,n,x;
int have_bed[MaxN],use_bed[MaxN],map[MaxN][MaxN];
int cns=0;//统计需要的床位数
int ans;//统计最大匹配数 
bool vis[MaxN];
int match[MaxN];
bool dfs(int u){
	for(int j=1;j<=n;j++){
		if(have_bed[j] && map[u][j] && !vis[j]){//遍历u可以睡的床位 
			vis[j]=1;
				//标记床位j要被u占用,从而match[j]递归
				//寻找床位时不会再尝试床位j 
			if(!match[j] || dfs(match[j])){
			    //床j还没有被占用,或者睡床j上的人可以到别的床去睡 
				match[j]=u;//床j让编号为u的人睡 
				return 1;
			}
		}
	}
	return 0;
}
void solve(){
	for(int i=1;i<=n;i++){
		memset(vis,0,sizeof(vis));
		if(use_bed[i]==0)//编号为i的人需要床位 
			if(dfs(i))//编号为i的人找到了床 
				ans++;
	}		
} 
int main(){
	cin>>T;
	while(T--){
		cin>>n;
		cns=0;
		for(int i=1;i<=n;i++){
			scanf("%d",&x);
			have_bed[i]=x;//若为1,则编号i的人为学生,有床位 
		}
		for(int i=1;i<=n;i++){
			scanf("%d",&x);
			if(!have_bed[i])x=0;//非在校生,需要用到床位 
			use_bed[i]=x;//若为0,表示编号i的人要用到床位 
			if(x==0)cns++;
		}
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++){
				scanf("%d",&map[i][j]);
				if(i==j)map[i][i]=1;	
			}
			
		//匈牙利算法
		memset(match,0,sizeof(match));
		ans=0;
		solve();
		
		if(ans>=cns)cout<<"^_^"<<endl;
		else cout<<"T_T"<<endl;
	}
}

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值