题意
这是一个简单的游戏,在一个n*n的矩阵中,找n个数使得这n个数都在不同的行和列里并且要求这n个数中的最大值和最小值的差值最小。
Input
输入一个整数T表示T组数据。
对于每组数据第一行输入一个正整数n(1<=n<=100)表示矩阵的大小。
接着输入n行,每行n个数x(0<=x<=100)。
Output
对于每组数据输出一个数表示最小差值。
思路
二分差值,看这个差值能否让所有的x坐标和y坐标都匹配。
如果能匹配,说明我们当前二分的差值偏大。
如果不能匹配,说明我们当前二分的差值偏小。
二分图匹配那里,当有一个x无法匹配到y时,直接结束。这样优化可以节省不少时间,避免TLE。
代码
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn = 110;
int G[maxn][maxn];
bool used[maxn];
int match[maxn];
int a[maxn][maxn];
int cnt = 0;//不同的数字有多少个
int unique_num[maxn * maxn];
int n;
bool dfs(int u){
for(int i = 1; i <= n; i++)
{
if(!used[i] && G[u][i])
{
used[i] = 1;
if(match[i] == -1|| dfs(match[i]))
{
match[i] = u;
return true;
}
}
}
return false;
}
int Hungary(){
int ans = 0;
memset(match, -1, sizeof(match));
for(int i = 1; i <= n; i++)
{
memset(used, 0, sizeof(used));
if(dfs(i))
{
ans++;
}else{
break;
}
}
return ans;
}
void get_unique(int num){
for(int i = 1; i <= cnt; i++)
{
if(num == unique_num[i])
return ;
}
unique_num[++cnt] = num;
}
int main(){
int t;
scanf("%d", &t);
while(t--)
{
cnt = 0;
scanf("%d", &n);
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
{
scanf("%d", &a[i][j]);
get_unique(a[i][j]);
}
int l = 0, r = 210, ans;
sort(unique_num + 1, unique_num + 1 + cnt);
while(l <= r)
{
int mid = (l + r) >> 1, flag = false;
for(int i = 1; i <= cnt; i++)//枚举下界(假设取了的数字中,最下的数字是它)
{
memset(G, 0, sizeof(G));
for(int j = 1; j <= n; j++)//在范围里面的就建边
for(int k = 1; k <= n; k++)
if(a[j][k] >= unique_num[i] && a[j][k] <= unique_num[i] + mid)
G[j][k] = 1;
int num = Hungary();
if(num == n)
{
flag = true;
break;
}
}
if(flag)//能够匹配,因为mid的值(差值)假设的偏大了
{
ans = mid;
r = mid - 1;
}else{
l = mid + 1;
}
}
printf("%d\n", ans);
}
return 0;
}