HDU 2236:无题II(二分搜索+二分匹配)
http://acm.hdu.edu.cn/showproblem.php?pid=2236
题意:中文题意。
思路:先找出最大和最小值,然后二分差值,对于每一个差值从下界开始枚举判断能不能二分匹配。
1 #include <cstdio> 2 #include <algorithm> 3 #include <iostream> 4 #include <cstring> 5 #include <string> 6 #include <cmath> 7 #include <queue> 8 #include <vector> 9 using namespace std; 10 #define N 105 11 #define INF 0x3f3f3f3f 12 bool vis[N]; 13 int match[N]; 14 int mp[N][N]; 15 int n, mi, ma, run, mid; 16 17 // 二分差值搜索枚举下界判断能不能成立 18 19 bool dfs(int u) 20 { 21 for(int i = 1; i <= n; i++) { 22 if(!vis[i]) { 23 if(mp[u][i] < run || mp[u][i] > run + mid) continue; // 这个数不能小于下界也不能大于上界 24 vis[i] = 1; 25 if(match[i] == -1 || dfs(match[i])) { 26 match[i] = u; 27 return true; 28 } 29 } 30 } 31 return false; 32 } 33 34 bool solve() // 匈牙利算法 35 { 36 memset(match, -1, sizeof(match)); 37 for(int i = 1; i <= n; i++) { 38 memset(vis, 0, sizeof(vis)); 39 if(!dfs(i)) return false; 40 } 41 return true; 42 } 43 44 int main() 45 { 46 int t; 47 scanf("%d", &t); 48 while(t--) { 49 scanf("%d", &n); 50 memset(mp, 0, sizeof(mp)); 51 mi = INF, ma = 0; 52 for(int i = 1; i <= n; i++) { 53 for(int j = 1; j <= n; j++) { 54 scanf("%d", &mp[i][j]); 55 if(mp[i][j] < mi) mi = mp[i][j]; 56 if(mp[i][j] > ma) ma = mp[i][j]; 57 } 58 } 59 int l = 0, r = ma - mi, ans; 60 while(l <= r) { 61 mid = (l + r) / 2; // 二分差值 62 bool f = 0; 63 for(run = mi; run + mid <= ma; run++) // 从下界开始枚举 64 if(solve()) { r = mid - 1; break; } 65 if(r != mid - 1) l = mid + 1; 66 // printf("%d, %d, %d\n", l, r, mid); 67 } 68 printf("%d\n", l); 69 } 70 return 0; 71 } 72 73 /* 74 2 75 4 76 1 2 1 1 77 2 2 2 2 78 3 3 3 3 79 4 4 4 4 80 4 81 1 1 1 1 82 1 2 2 2 83 3 1 3 3 84 4 4 1 4 85 */