首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > 编程 >

[2分枚举+匈牙利]hdoj 2236:无题II

2012-09-08 
[二分枚举+匈牙利]hdoj 2236:无题II大致题意:? ??在一个n*n的矩阵中,找n个数使得这n个数都在不同的行和列

[二分枚举+匈牙利]hdoj 2236:无题II

大致题意:
? ??在一个n*n的矩阵中,找n个数使得这n个数都在不同的行和列里并且要求这n个数中的最大值和最小值的差值最小。

?

大致思路:

? ? 看到了“最大最小”其实就应该想到是要用二分。这道题也是如此,首先二分枚举这个最大差值,再枚举下限,用匈牙利算法来验证枚举是否成立即可。但是这样做依然会tle,所以要加入一个辅助数组,来记录哪些数字曾经出现过,从而在枚举下界的时候可以避开那些无用的数字。

?

?

#include<iostream>#include<cstring>#include<cstdio>using namespace std;const int nMax=104;const int mMax=105;const int inf=1<<30;int n,m;int map[nMax][nMax];bool vis[mMax];int linkk[mMax];int dfs(int s){    for(int i=1;i<=m;i++){        if(!vis[i]&&map[s][i]){            vis[i]=1;            if(linkk[i]==-1||dfs(linkk[i])){                linkk[i]=s;                return 1;            }        }    }    return 0;}bool app[101];int num[nMax][nMax],sma,big;bool check(int mid){    int i,j,ans;    for(int k=sma;k+mid<=big;k++){  //枚举下界        if(!app[k])continue;        ans=0;        for(i=1;i<=n;i++){            for(j=1;j<=n;j++){                if(num[i][j]>=k&&num[i][j]<=k+mid){                    map[i][j]=1;                }else {                    map[i][j]=0;                }                  //  cout<<map[i][j];            }//cout<<endl;        }        memset(linkk,-1,sizeof(linkk));        for(i=1;i<=n;i++){            memset(vis,0,sizeof(vis));            if(dfs(i))ans++;            if(ans==n)return 1;        }    }    return 0;}int main(){    int i,j,cas,ans;    scanf("%d",&cas);    while(cas--){        sma=inf;        big=-1;        scanf("%d",&n);        m=n;        memset(app,0,sizeof(app));        for(i=1;i<=n;i++){            for(j=1;j<=n;j++){                scanf("%d",&num[i][j]);                sma=min(num[i][j],sma);                big=max(num[i][j],big);                app[num[i][j]]=1;            }        }        int left=0,right=big-sma+1,mid;//开始二分        while(right>=left){            mid=(right+left)/2;            if(check(mid)){                right=mid-1;                ans=mid;            }            else{                left=mid+1;            }        }        printf("%d\n",ans);    }    return 0;}

热点排行