无题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)。
对于每组数据第一行输入一个正整数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 }