HDOJ---2236 无题II[二分枚举+匈牙利]

无题II

Time Limit: 2000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 571    Accepted Submission(s): 296


Problem Description
这是一个简单的游戏,在一个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
 

 

Author
xhd
 

 

Source
 

 

Recommend
lcy
 
 
 
 
 
 
 
 
code :
  1 /*

  2 为了保证每行每列只取一个元素,我们可以从二分图最大匹配的思想入手,把行和列分别看做二分图左右两部分,

  3 i-j的边权就是第i行第j列的元素的值。这样构图之后,求得的二分图最大匹配的4条边就是不在同行或同列的4个元素。

  4 有了这个思想时候,我们只需要再保证4个元素中最大值与最小值之差尽量小就可以了,于是我们可以二分枚举最大值与最小值之差,

  5 并枚举边权值的下界,如果枚举到某个边权值的下界时该图存在最大匹配,那么就更新max,否则就更新min。

  6 */

  7 #include <iostream>   

  8 #include <iomanip>   

  9 #include <fstream>   

 10 #include <sstream>   

 11 #include <algorithm>   

 12 #include <string>   

 13 #include <set>   

 14 #include <utility>   

 15 #include <queue>   

 16 #include <stack>   

 17 #include <list>   

 18 #include <vector>   

 19 #include <cstdio>   

 20 #include <cstdlib>   

 21 #include <cstring>   

 22 #include <cmath>   

 23 #include <ctime>   

 24 #include <ctype.h> 

 25 using namespace std;

 26 

 27 #define MAXN 110

 28 

 29 int map[MAXN][MAXN];

 30 int vst[MAXN];

 31 int path[MAXN];

 32 int n;

 33 int p;

 34 int minnum,maxnum,midnum;

 35 

 36 bool dfs(int v)

 37 {

 38     for(int i=0;i<n;i++)

 39         if(map[v][i]>=p&&map[v][i]<=p+midnum&&!vst[i])

 40         {

 41             vst[i]=1;

 42             if(path[i]==-1||dfs(path[i]))

 43             {

 44                 path[i]=v;

 45                 return true;

 46             }

 47         }

 48     return false;

 49 }

 50 

 51 bool hungary()

 52 {

 53     memset(path,-1,sizeof(path));

 54     for(int i=0;i<n;i++)

 55     {

 56         memset(vst,0,sizeof(vst));

 57         if(!dfs(i))                                //一旦发现有横坐标没有对应的y坐标与其匹配就return false

 58             return false;

 59     }

 60     return true;                       //表示所有的横坐标已经全部匹配,return true

 61 }

 62 

 63 int main()

 64 {

 65     int t;

 66     int i,j;

 67     scanf("%d",&t);

 68     while(t--)

 69     {

 70         int gmax=0,gmin=101;

 71         scanf("%d",&n);

 72         for(i=0;i<n;i++)

 73             for(j=0;j<n;j++)

 74             {

 75                 scanf("%d",&map[i][j]);

 76                 gmax=gmax>map[i][j]?gmax:map[i][j];

 77                 gmin=gmin<map[i][j]?gmin:map[i][j];

 78             }

 79         maxnum=gmax-gmin;

 80         minnum=0;

 81         while(1)

 82         {

 83             bool flag=false;

 84             midnum=(maxnum+minnum)/2;

 85             for(p=gmin;p+midnum<=gmax;p++)

 86             {

 87                 if(hungary())

 88                 {

 89                     flag=true;

 90                     break;

 91                 }

 92             }

 93             if(flag)

 94                 maxnum=midnum;

 95             if(midnum==minnum)                  //注意:这三个if的顺序不能随意颠倒

 96                 break;

 97             if(!flag)

 98                 minnum=midnum;            

 99         }

100         printf("%d\n",maxnum);

101     }

102     return 0;

103 }

 

你可能感兴趣的:(枚举)