hdu 2236(二分图最小点覆盖+二分)

无题II

Time Limit: 2000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1545    Accepted Submission(s): 692


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
 

 

Author
xhd
 

 

Source
 
题解:二分枚举差值,然后枚举下界,建造出另一个图,做一次最小点覆盖,如果最小点覆盖值为n,则证明当前差值可行。时间复杂度有点高。。
#include<iostream>
#include<cstdio>
#include<cstring>
#include <algorithm>
#include <math.h>
using namespace std;
const int N = 105;
int n,MIN,MAX;
int graph[N][N],mp[N][N];
int linker[N];
bool vis[N];
bool dfs(int u)
{
    for(int v=1; v<=n; v++)
    {
        if(!vis[v]&&mp[u][v])
        {
            vis[v] = true;
            if(linker[v]==-1||dfs(linker[v]))
            {
                linker[v] = u;
                return true;
            }
        }
    }
    return false;
}
bool match(int mid)
{
    int k = MAX - mid;
    for(int i=1; i<=k; i++)
    {
        for(int j=1; j<=n; j++)
        {
            for(int k=1; k<=n; k++)
            {
                if(graph[j][k]<=i+mid&&graph[j][k]>=i) mp[j][k] = 1;
                else mp[j][k]=0;
            }
        }
        memset(linker,-1,sizeof(linker));
        int res = 0;
        for(int u=1; u<=n; u++)
        {
            memset(vis,false,sizeof(vis));
            if(dfs(u)) res++;
        }
        if(res==n) return true;
    }
    return false;
}
int main()
{
    int tcase;
    scanf("%d",&tcase);
    while(tcase--)
    {
        scanf("%d",&n);
        MIN=99999999,MAX=-1;
        for(int i=1; i<=n; i++)
        {
            for(int j=1; j<=n; j++)
            {
                scanf("%d",&graph[i][j]);
                MIN = min(MIN,graph[i][j]);
                MAX = max(MAX,graph[i][j]);
            }
        }
        int l = MIN,r = MAX,ans = MAX-MIN;
        while(l<=r)
        {
            int mid = (l+r)>>1;
            if(match(mid))
            {
                ans = mid;
                r = mid-1;
            }
            else l=mid+1;
        }
        printf("%d\n",ans);
    }
    return 0;
}

 

posted @ 2016-07-28 22:14  樱花庄的龙之介大人  阅读(174)  评论(0编辑  收藏  举报