无题II hdu2236
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
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#define C(i,x) memset(i,x,sizeof(i))
using namespace std;
template<typename T>void read(T &x)
{
char ch;
int f=1;
x=0;
for(; ch<'0'||ch>'9'; ch=getchar())
if(ch=='-')
f=-1;
for(; ch>='0'&&ch<='9'; ch=getchar())
x=(x<<1)+(x<<3)+(ch&15);
x*=f;
}
template<typename T>void print(T x)
{
if(x<0)
x*=-1,putchar('-');
if(x>=10)
print(x/10);
putchar(x%10+'0');
}
const int N=200;
const int INF=0x3f3f3f3f;
int minn=INF;
int p,mid=0;
int nxe[N],used[N],mp[N][N];
int n;
bool Find(int x)
{
for(int i=0; i<n; i++)
{
if(!used[i]&&mp[x][i]>=p&&mp[x][i]<=p+mid)
{
used[i]=1;
if(nxe[i]==-1||Find(nxe[i]))
{
nxe[i]=x;
return true;
}
}
}
return false;
}
bool match()
{
C(nxe,-1);
// memset(nxe,-1,sizeof(nxe));
for(int i=0; i<n; i++)
{
C(used,0);
// memset(used,0,sizeof(used));
if(!Find(i))
{
return false; //返回false ,若倒过来返回true 是错误的。
}
}
return true;
}
int main()
{
ios::sync_with_stdio(false);
int t;
read(t);
while(t--)
{
//cin>>n;
read(n);
int mx=-INF,mi=INF;
for(int i=0; i<n; i++)
for(int j=0; j<n; j++)
{
read(mp[i][j]);
mx=max(mx,mp[i][j]);
mi=min(mi,mp[i][j]);
}
int l=0,r=mx-mi;
int f=0;
int res;
while(l<=r)
{
mid=(l+r)>>1;
f=0;
for(p=mi; p+mid<=mx; p++)
{
if(match())
{
f=1;
break;
}
}
if(f)
res=mid,r=mid-1;
else
l=mid+1;
}
print(res);
puts("");
}
return 0;
}
思路
二分图的完美匹配。(行列分为两个集合,则每个顶点必定会被匹配到,否则匹配不到n个)
二分查找差值;逐步缩小差值。
ps:
要注意nxe数组初始化为-1; 因为点有0的值的情况,所以判断未匹配用-1表示。