此题参考了 西瓜不懂柠檬的酸 dalao的博客 点击打开链接
/** 中文题,自己好好理解一下题意。 想到基本算法很简单,就是一个匈牙利算法,但是,难点在于,如何使得最大值,最小值的差最小 要求最大值与最小值的差值最小,是通过枚举边的下限和上限来完成 只需要用二分找一个区间,然后不断枚举这个区间是否可以达到最大匹配,一直二分到答案为止。*/ #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int Maxx=105; const int inf=0x3f3f3f3f; int link[Maxx][Maxx],match[Maxx],vis[Maxx]; int MaxR,MinL,Max,Min,R,L,n;///MaxR,MinL记录最大最小值,Max,Min记录区间的上下限,L,R记录二分查找差值的上下限// bool dfs(int x) { for(int i=1;i<=n;i++){ if(!vis[i]&&link[x][i]>=Min&&link[x][i]<=Max){ vis[i]=1; if(!match[i]||dfs(match[i])){ match[i]=x; return 1; } } } return 0; } bool hungary()///匈牙利算法 { memset(match,0,sizeof match); for(int i=1;i<=n;i++){ memset(vis,0,sizeof vis); if(!dfs(i)) return 0; } return 1; } int main() { int t; scanf("%d",&t); while(t--){ memset(link,0,sizeof link); MaxR=-1,MinL=inf; scanf("%d",&n); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++){ scanf("%d",&link[i][j]); MaxR=max(MaxR,link[i][j]); MinL=min(MinL,link[i][j]); } L=0; R=MaxR-MinL;///差值的的上下限 int ans=0; while(L<=R){ int flag=0; int mid=(L+R)/2; for(int i=MinL;i+mid<=MaxR;i++){ Min=i;///如果差值为mid,那么,查找一个区间是,这个区间的最小值为i,最大值为i+mid Max=i+mid; if(hungary()){///如果在值在区间i,i+mid之间,并且可以完成匹配,那么说明可能存在一个差值比mid还要小,所以令上界减一,否则令下界加一 flag=1; break; } } if(flag){///上界减一,使得差值变小 ans=mid; R=mid-1; } else///下界加一,使得差值变大 L=mid+1; } printf("%d ",ans); } return 0; }