杭电oj 2236 无题II(二分+匈牙利)

本题链接

题目

题目描述

这是一个简单的游戏,在一个n*n的矩阵中,找n个数使得这n个数都在不同的行和列里并且要求这n个数中的最大值和最小值的差值最小。

输入

输入一个整数T表示T组数据。
对于每组数据第一行输入一个正整数n(1<=n<=100)表示矩阵的大小。
接着输入n行,每行n个数x(0<=x<=100)。

输出

对于每组数据输出一个数表示最小差值。

Sample Input

1
4
1 1 1 1
2 2 2 2
3 3 3 3
4 4 4 4

Sample Output

3

思路:

第一眼以为是搜索,没想到能用二分图匹配思想做出orz
因为是不同行不同列,可以分别将行和列作为二分图的两部分,然后二分差值,易知 0 <= 差值 <= max-min ,所以二分的 left=0right=max-min,然后枚举在min,min+差值的范围中能否使每行都找到匹配(匈牙利算法),能就再缩小答案

代码:

#include <bits/stdc++.h>
using namespace std;
const int maxn=1e2+10;
#define faster ios::sync_with_stdio(false);cin.tie(0),cout.tie(0)
int link[maxn][maxn],use[maxn],ptn[maxn];
int n,mid,p;
bool find(int x){
    for (int i = 1; i <= n; ++i) {
        if (link[x][i]>=p&&link[x][i]<=p+mid&&!use[i]){
            use[i]=1;
            if (ptn[i]==-1|| find(ptn[i])){
                ptn[i]=x;
                return true;
            }
        }
    }
    return false;
}
bool match(){
    memset(ptn,-1,sizeof ptn);
    for (int i = 1; i <= n; ++i) {
        memset(use,0,sizeof use);
        if (!find(i)) return false;
    }
    return true;
}
signed main(){
    faster;
    int T;
    scanf("%d",&T);
    while (T--){
        scanf("%d",&n);
        int mi=105,ma=-5;
        for (int i = 1; i <= n; ++i) {
            for (int j = 1; j <= n ; ++j) {
                scanf("%d",&link[i][j]);
                ma=link[i][j]>ma?link[i][j]:ma;
                mi=link[i][j]<mi?link[i][j]:mi;
            }
        }
        int r=ma-mi,l=0;
        while (r>=l){
            int flag=0;
            mid=(r+l)>>1;
            for (p = mi; p+mid <= ma; ++p) {
                if(match()){
                    flag=1;
                    break;
                }
            }
            if(flag) r=mid-1;
            else l=mid+1;
        }
        printf("%d\n",l);
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值