hdu2336 (匈牙利最大匹配+二分)

Posted lour688

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了hdu2336 (匈牙利最大匹配+二分)相关的知识,希望对你有一定的参考价值。

Describe

这是一个简单的游戏,在一个n*n的矩阵中,找n个数使得这n个数都在不同的行和列里并且要求这n个数中的最大值和最小值的差值最小。

Input

输入一个整数T表示T组数据。
对于每组数据第一行输入一个正整数n(1<=n<=100)表示矩阵的大小。
接着输入n行,每行n个数x(0<=x<=100)。

Output

对于每组数据输出一个数表示最小差值。

Sample Input

1
4
1 1 1 1
2 2 2 2
3 3 3 3
4 4 4 4

Sample Output

3

Solution

首先因为每列每行只能选一个数,自然想到二分图匹配,让行作为左部,列作为右部,让列与行去匹配,当形成完备匹配(左右部点数相等,左部每个点都有对应的匹配点)时,则可取.

题目中要问最小的极值差,且n范围很小[1,100],所以我们枚举区间len,看看权值在某一区间[ l , l+len ]中的边能否使图形成完备匹配.左端点枚举.对于区间我们用二分.

Code

#include <cmath>
#include <cstdio>
#include <cstring> 
#include <algorithm>
using namespace std;
const int maxn=100+5,Inf=0x3f3f3f3f;
int n,mat[maxn],rel[maxn][maxn],Max,Min;
bool vis[maxn];
bool Find(int u,int l,int r){
	for(int i=1;i<=n;++i){
		if(rel[u][i]<l||rel[u][i]>r)continue;
		if(!vis[i]){
			vis[i]=1;
			if(!mat[i]||Find(mat[i],l,r)){
				mat[i]=u;return 1;
			}
		}
	}
	return 0;
}
bool cd(int l,int r){
	memset(mat,0,sizeof mat);
	int cnt=0;
	for(int i=1;i<=n;++i){
		memset(vis,0,sizeof vis);
		if(Find(i,l,r))cnt++;
	}
	if(cnt==n)return 1;
	else return 0;
}
int main(){
	int t;scanf("%d",&t);
	while(t--){
		Max=0,Min=Inf;
		scanf("%d",&n);
		for(int i=1;i<=n;++i){
			for(int j=1;j<=n;++j){
				scanf("%d",&rel[i][j]);
				Max=max(Max,rel[i][j]);
				Min=min(Min,rel[i][j]);
			}
		}
		int l=0,r=Max-Min,ans=r;//l是区间最小值,r是区间最大值
		while(l<=r){
			int mid=((l+r)>>1);//这个外面应该加一层括号,mid是区间长度
			bool fg=0;
			for(int i=Min;i+mid<=Max;++i){//枚举左端点
				if(cd(i,i+mid)){
					ans=min(ans,mid);
					fg=1;
					break;
				}
			}
			if(fg)r=mid-1;
			else l=mid+1;
		}
		printf("%d
",ans);
	}
	return 0;
}


以上是关于hdu2336 (匈牙利最大匹配+二分)的主要内容,如果未能解决你的问题,请参考以下文章

hdu2063 匈牙利算法 二分最大匹配模版题

hdu2063 最大二分匹配(匈牙利算法)

HDU - 1045 Fire Net (二分图最大匹配-匈牙利算法)

hdu 2063 过山车 二分图的最大匹配 匈牙利算法

HDU - 1083 Courses (二分图最大匹配模板)

01染色法判断二分匹配+匈牙利算法求最大匹配HDU The Accomodation of Students