无题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表示。

posted @ 2019-12-03 18:01  Anticlock  阅读(168)  评论(0编辑  收藏  举报