HDU2236

分析

题干很简单,每行每列只能选一个,所以想到了状压DP???然后发现压不下来。。。
于是又想到之前的一道将行和列连边的二分图的题,发现这个也可以。
然后就只剩下了怎么求最小值,因为\(n\)的范围较小,所以可以尝试去把所有可能的答案枚举一下,直接枚举显然不可,所以要用到二分答案。
所以就是先求出最大的答案,然后开始逐步缩小,遇到合法的就更新,最后输出。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=1e2+10;
int g[N][N],n;
int match[N],vis[N];
bool dfs(int x,int l,int r){
    for(int i=1;i<=n;i++){
        if(vis[i]||g[x][i]>r||g[x][i]<l)continue;
        vis[i]=1314;
        if(match[i]==-1||dfs(match[i],l,r)){
            match[i]=x;
            return 1;
        }
    }
    return 0;
}
bool check(int l,int r){
    memset(match,-1,sizeof(match));
    for(int i=1;i<=n;i++){
        memset(vis,0,sizeof(vis));
        if(!dfs(i,l,r))return 0;
    }
    return 1;
}
int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        int minn=0x3f3f3f3f;
        int maxx=0;
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++){
                scanf("%d",&g[i][j]);
                maxx=max(g[i][j],maxx);
                minn=min(g[i][j],minn);
            }
        int l=0,r=maxx-minn;
        int ans=r;
        while(l<=r){
            int mid=l+r>>1;
            bool is=0;
            for(int i=minn;i+mid<=maxx;i++)
                if(check(i,i+mid)){
                    is=1;break;
                }
            if(is){
                ans=mid;
                r=mid-1;
            }else l=mid+1;
        }
        printf("%d\n",ans);
    }
}
posted @ 2020-05-11 23:06  An_Fly  阅读(95)  评论(0编辑  收藏  举报