hdu2236 无题II
传送门
在一个(n*n)的矩阵(a)中,选择(n)个不同行、不同列的元素,使得其中最大值与最小值的差值最小
(1leq nleq 100),(0leq a_{ij} leq 100)
由于每一行、每一列只能选择一个元素,可以将行号和列号分成两个集合,建立二分图。
二分答案,遍历所有不同的元素,设定为下界,将矩阵中所有符合条件的元素行号和列号之间连边,通过匈牙利算法判断当前答案是否可行
时间复杂度(O(n^4log n))
#include<iostream>
#include<cstdio>
#include<vector>
#include<stack>
#include<queue>
#include<set>
#include<map>
#include<cstring>
#include<string>
#include<sstream>
#include<cmath>
#include<ctime>
#include<algorithm>
#define LL long long
#define PII pair<int,int>
#define PLL pair<LL,LL>
#define pi acos(-1.0)
#define eps 1e-6
#define lowbit(x) x&(-x)
using namespace std;
const int maxn=110;
int T,n,m,a[maxn][maxn],line[maxn][maxn],match[maxn],book[maxn];
set<int> s;
bool find(int u){
for(int i=1;i<=m;i++){
if(line[u][i] && !book[i]){
book[i]=1;
if(!match[i] || find(match[i])){
match[i]=u;
return true;
}
}
}
return false;
}
int matching(){
int res=0;
for(int i=1;i<=n;i++){
memset(book,0,sizeof(book));
if(find(i)) res++;
}
return res;
}
bool check(int diff){
set<int>::iterator it;
for(it=s.begin();it!=s.end();it++){
int mini=*it;
memset(line,0,sizeof(line));
memset(match,0,sizeof(match));
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(a[i][j]>=mini && a[i][j]<=mini+diff) line[i][j]=1;
}
}
if(matching()==n) return true;
}
return false;
}
int main(){
scanf("%d",&T);
while(T--){
scanf("%d",&n);
s.clear();
m=n;
int mini=110,maxi=-1;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
scanf("%d",&a[i][j]);
mini=min(mini,a[i][j]);
maxi=max(maxi,a[i][j]);
s.insert(a[i][j]);
}
}
int l=0,r=maxi-mini;
while(r>l){
int mid=(l+r)>>1;
if(check(mid)) r=mid;
else l=mid+1;
}
printf("%d
",r);
}
return 0;
}