这是一个简单的游戏,在一个n*n的矩阵中,找n个数使得这n个数都在不同的行和列里并且要求这n个数中的最大值和最小值的差值最小。
这道题是道不错的二分图题
首先要对答案进行二分了,这个很自然就想到了;
但在后面对二分是否符合的判断思路卡住了
后面才想到使用枚举从(最小值,最小值+二分的差值)枚举这个区间进行行列匹配。好题!!!
详情见如下代码
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#include <queue>
using namespace std;
const int N=3e3+10;
const int M=1e7+10;
const int inf=0x3f3f3f3f;
int head[N],cnt;
struct edge{
int next,to;
}e[M];
void add(int u,int v){
e[cnt].to=v;
e[cnt].next=head[u];
head[u]=cnt++;
}
int mp[105][105],minn,maxn,n;
bool vis[N];
int match[N];
bool dfs(int x,int l,int r){
for(int i=1;i<=n;++i){
if(!vis[i]&&mp[x][i]>=l&&mp[x][i]<=r){
vis[i]=1;
if(match[i]==-1||dfs(match[i],l,r)){
match[i]=x;
return true;
}
}
}
return false;
}
bool solve(int l,int r){
memset(match,-1,sizeof match);
for(int i=1;i<=n;++i){
memset(vis,false,sizeof vis);
if(!dfs(i,l,r)) return false;
}
return true;
}
bool check(int t){
for(int i=minn;i<=maxn-t;++i){
if(solve(i,i+t)) return true;
}
return false;
}
int main(){
int T;scanf("%d",&T);
while(T--){
scanf("%d",&n);
minn=inf,maxn=0;
for(int i=1;i<=n;++i){
for(int j=1;j<=n;++j){
scanf("%d",&mp[i][j]);
minn=min(minn,mp[i][j]);
maxn=max(maxn,mp[i][j]);
}
}
int l=0,r=maxn-minn,ans;
while(l<=r){
int mid=l+r>>1;
if(check(mid)){
r=mid-1,ans=mid;
}
else l=mid+1;
}
printf("%d\n",ans);
}
return 0;
}