分析
题干很简单,每行每列只能选一个,所以想到了状压DP???然后发现压不下来。。。
于是又想到之前的一道将行和列连边的二分图的题,发现这个也可以。
然后就只剩下了怎么求最小值,因为(n)的范围较小,所以可以尝试去把所有可能的答案枚举一下,直接枚举显然不可,所以要用到二分答案。
所以就是先求出最大的答案,然后开始逐步缩小,遇到合法的就更新,最后输出。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=1e2+10;
int g[N][N],n;
int match[N],vis[N];
bool dfs(int x,int l,int r){
for(int i=1;i<=n;i++){
if(vis[i]||g[x][i]>r||g[x][i]<l)continue;
vis[i]=1314;
if(match[i]==-1||dfs(match[i],l,r)){
match[i]=x;
return 1;
}
}
return 0;
}
bool check(int l,int r){
memset(match,-1,sizeof(match));
for(int i=1;i<=n;i++){
memset(vis,0,sizeof(vis));
if(!dfs(i,l,r))return 0;
}
return 1;
}
int main(){
int T;
scanf("%d",&T);
while(T--){
int minn=0x3f3f3f3f;
int maxx=0;
scanf("%d",&n);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++){
scanf("%d",&g[i][j]);
maxx=max(g[i][j],maxx);
minn=min(g[i][j],minn);
}
int l=0,r=maxx-minn;
int ans=r;
while(l<=r){
int mid=l+r>>1;
bool is=0;
for(int i=minn;i+mid<=maxx;i++)
if(check(i,i+mid)){
is=1;break;
}
if(is){
ans=mid;
r=mid-1;
}else l=mid+1;
}
printf("%d
",ans);
}
}