题目:http://acm.hdu.edu.cn/showproblem.php?pid=2236
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
对于每组数据输出一个数表示最小差值。
在KM算法专题里面碰到的这道题,分到里面不太合适,应该分到匈牙利算法专题里面,被误导了。。。
想了好几天没有头绪,于是百度了一下, 看看大神们的写法,二分真是个神奇的东西,怪我理解不够深。。。
找出n*n个元素的最大值vmax和最小值vmin,那么差值一定在l=0到r=(vmax-vmin)之间,于是二分枚举差值进行匹配,在当前差值下能够完全匹配,那么更新r,同时保存当前差值,否则更新l。二分查到完毕后,输出之前保存的差值,就是结果
#include <iostream>
#include <string>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cctype>
#include <vector>
#include <map>
using namespace std;
const int N = 110;
const int INF = 0x3f3f3f3f;
int match[N];
int mpa[N][N];
int p, mid, n;
bool used[N];
bool dfs(int v)
{
for(int i = 0; i < n; i++)
if(mpa[v][i] >= p && mpa[v][i] <= p + mid && used[i] == false)//匹配条件要稍作修改,不是简单匈牙利模板
{
used[i] = true;
if(match[i] == -1 || dfs(match[i]))
{
match[i] = v;
return true;
}
}
return false;
}
bool hungary()
{
memset(match, -1, sizeof match);
for(int i = 0; i < n; i++)
{
memset(used, 0, sizeof used);
if(! dfs(i)) return false;
}
return true;
}
int main()
{
int t;
scanf("%d", &t);
while(t--)
{
scanf("%d", &n);
int vmax = -INF, vmin = INF;
for(int i = 0; i < n; i++)
for(int j = 0; j < n; j++)
{
scanf("%d", &mpa[i][j]);
vmax = max(vmax, mpa[i][j]);
vmin = min(vmin, mpa[i][j]);
}
int r = vmax - vmin, l = 0, res;
while(l <= r) //发现大神们的二分姿势好奇怪,这个姿势是我的
{
mid = (l + r) >> 1;
bool f = false;
for(p = vmin; p + mid <= vmax; p++)
if(hungary())
{
f = true;
break;
}
if(f) res = mid, r = mid - 1;
else l = mid + 1;
}
printf("%d\n", res);
}
return 0;
}