无题II HDU - 2236 【二分图+二分答案】

这是一个简单的游戏,在一个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=1时的正确答案。

跑匈牙利的时候枚举上下界【二分出来的上下界】。

#include <bits/stdc++.h>
#define ms(x) memset(x, 0, sizeof(x))
#define inf 0x3f3f3f3f
#define mf(x) memset(x, inf, sizeof(x))
#define mf1(x) memset(x, -1, sizeof(x))
using namespace std;
const int N = 101;
const int M = 10103;
int uN, vN;
int a[N][N];
bool used[N];
int linker[N];
bool dfs(int u, int ll, int rr) {
    for(int v=1; v<=uN; v++) {
        if(a[u][v] >=ll && a[u][v]<=rr && !used[v]) {
            used[v] = true;
            if(linker[v] == -1 || dfs(linker[v], ll, rr)) {
                linker[v] = u;
                return true;
            }
        }
    }
    return false;
}
bool hungry(int mid, int ll , int rr) {
    int res = 0;
    mf1(linker);
    for(int u=1; u<=uN; u++) {
        ms(used);
        if(!dfs(u, ll , rr)) return false;
    }
    return true;
}
bool check(int mid){
    for(int i=0;i+mid<=100;i++){
        if(hungry(mid, i, i+mid)){
            return true;
        }
    }
    return false;
}
int main() {
    int T;
    scanf("%d", &T);
    while(T--) {
        int n;
        scanf("%d", &n);
        uN = vN = n;
        int mi = inf, ma = -1;
        for(int i=1; i<=n; i++)
            for(int j=1; j<=n; j++) {
                scanf("%d",&a[i][j]);
                mi = min(mi, a[i][j]);
                ma = max(ma, a[i][j]);
            }
        int l = 0, r = ma - mi;
        while(l<=r) {
            int mid = (l+r)>>1;
            if(check(mid)) {
                r = mid-1;
            } else l = mid+1;
        }
        printf("%d\n", l);
    }
    return 0;
}


猜你喜欢

转载自blog.csdn.net/khn64/article/details/80661642