无题 II 二分图最大匹配

题目描述

这是一个简单的游戏,在一个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

分析

因为这(n)个数都在不同的行和列,所以我们可以把这看成一个冲突条件,可以很容易地联想到二分图的最大匹配

但是匹配的时候要修改一下匹配的条件,即用一个(mmin)和一个(mmax)限定所选的价值

然后枚举最小差值的时候要用到二分

代码

#include<cstdio>
#include<map>
#include<iostream>
#include<algorithm>
#include<utility>
#include<cstring>
using namespace std;
const int maxn=105;
int a[maxn][maxn];
int n,l,r,mids,mmax,mmin;
bool vis[maxn];
int match[maxn],now;
int dfs(int xx){
    for(int i=1;i<=n;i++){
        if(now<=a[xx][i] && now+mids>=a[xx][i] && !vis[i]){
            vis[i]=1;
            if(match[i]==-1 || dfs(match[i])){
                match[i]=xx;
                return 1;
            }
        }
    }
    return 0;
}
int solve(){
    int cnt=0;
    memset(match,-1,sizeof(match));
    for(int i=1;i<=n;i++){
        memset(vis,0,sizeof(vis));
        cnt+=dfs(i);
    }
    if(cnt==n) return 1;
    return 0;
}
int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        mmax=-0x3f3f3f3f;
        mmin=0x3f3f3f3f;
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                scanf("%d",&a[i][j]);
                mmax=max(mmax,a[i][j]);
                mmin=min(mmin,a[i][j]);
            }
        }
        l=0,r=mmax-mmin;
        int ans=0;
        while(l<=r){
            mids=(l+r)>>1;
            bool jud=0;
            for(now=mmin;now+mids<=mmax;now++){
                if(solve()){
                    jud=1;
                    break;
                } 
            }
            if(jud) ans=mids,r=mids-1;
            else l=mids+1;
        }
        printf("%d
",ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/liuchanglc/p/12879572.html