HDU 2236 二分+二分图匹配

HDU  无题II

在不同的行和列里,是将行和列看做成连个没有交集的集合,这里可以看成是二分图的匹配

要求是将最大值与最小值的差值最小化,那就是通过二分进行枚举,不断地缩减它的上界与下界

#include <iostream>
#include <string>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include<cmath>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;i++)
const int INF=0x3f3f3f3f;
int n;
bool e[110][110];
int val[110][110];
int link[110];
bool vis[110];
int ans;
bool dfs(int x)
{
    rep(i,1,n)
    {
        if(!vis[i]&&e[x][i])
        {
            vis[i]=1;
            if((link[i]==0)||(dfs(link[i])))
            {
                link[i]=x;return true;
            }
        }
    }
    return false;
}
void add()
{
   ans=0;
   memset(link,0,sizeof link);
   rep(i,1,n)//i可以看成行集合
   {
       memset(vis,0,sizeof vis);
       if(!dfs(i)) return;
       ans++;
   }
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int minn=INF;
        int maxx=-INF;
        memset(val,0,sizeof val);
        scanf("%d",&n);
        rep(i,1,n)
        rep(j,1,n)
        scanf("%d",&val[i][j]),minn=min(minn,val[i][j]),maxx=max(maxx,val[i][j]);
        int l=0;//下界一定要从0开始否则就会WA
        int r=maxx-minn;//上届可以是最大值,但是在n*n的矩阵里最大值与最小值的差值最大为这个
        int res;
        memset(e,0,sizeof e);
        while(l<=r)//二分枚举
        {
            int mid=(l+r)>>1;
           for(int k=minn;k+mid<=maxx;k++){//从最小的值开始
            rep(i,1,n)
            rep(j,1,n)//这里的e数组是保存满足当前差值为mid的元素在哪个位置
            if(val[i][j]<=k+mid&&val[i][j]>=k)
                e[i][j]=1;
                else e[i][j]=0;
            add();//匈牙利模板
            if(ans==n) break;//如果当前的mid(最小的差值)满足行与列的完美匹配,跳出
            }
            if(ans==n) res=mid,r=mid-1;//说明当前的差值可能大一些,那就将其减小,继续二分
            else l=mid+1;
        }
        printf("%d\n",res);
    }

}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值