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 }

 

posted @ 2012-08-14 16:14  max_xbw  阅读(213)  评论(0)    收藏  举报