• bzoj-4433 小凸玩矩阵(二分图,二分+匈牙利)


    4443: [Scoi2015]小凸玩矩阵

    Description

    小凸和小方是好朋友,小方给小凸一个N*M(N<=M)的矩阵A,要求小秃从其中选出N个数,其中任意两个数字不能在同一行或同一列,现小凸想知道选出来的N个数中第K大的数字的最小值是多少。

    Input

    第一行给出三个整数N,M,K
    接下来N行,每行M个数字,用来描述这个矩阵

    Output

    如题 

    Sample Input

    3 4 2
    1 5 6 6 
    8 3 4 3
    6 8 6 3

    Sample Output

    3

    HINT

    1<=K<=N<=M<=250,1<=矩阵元素<=10^9

    题目大意:不多说了。。

    解题思路:看到第k大的数的最小值这种东西首先想到二分,这题把二分和二分图结合在一起。。终于做出了一题不是模板的题。。接下来具体说说怎么二分。二分枚举k,然后每次都先清空边,遍历一遍边,把小于等于k的边加进去。然后套匈牙利模板就行。如果满足,r=mid(因为可能刚好是mid,所以不能是r=mid-1),不满足则是l=mid+1。

    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    using namespace std;
    const int maxn=255;
    bool line[maxn][maxn],used[maxn];
    int a[maxn][maxn];
    int girl[maxn],n,m,k;
    
    bool dfs(int x)
    {
        int i,j;
        for(j=1;j<=m;j++)
        {
            if(line[x][j]==true&&used[j]==false)
            {
                used[j]=true;
                if(girl[j]==0||dfs(girl[j]))
                {
                    girl[j] = x;
                    return true;
                }
            }
        }
        return false;
    }
    
    int cal()
    {
        int ans=0;
        memset(girl,0,sizeof(girl));
        for(int i=1;i<=n;i++)
        {
            memset(used,false,sizeof(used));
            if(dfs(i))
            {
                ans++;
            }
        }
        return ans;
    }
    
    bool check(int mid)
    {
        memset(line,0,sizeof(line));
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
            {
                if(a[i][j]<=mid)
                {
                    line[i][j] = 1;
                }
            }
        }
        int ans=cal();
        if(ans>=k)
            return true;
        else
            return false;
    }
    
    int main()
    {
        while(scanf("%d %d %d",&n,&m,&k)!=EOF)
        {
            k=n-k+1;
            memset(line,false,sizeof(line));
            int x,y,maxl=1;
            for(int i=1;i<=n;i++)
            {
                for(int j=1;j<=m;j++)
                {
                    scanf("%d",&a[i][j]);
                    maxl = max(maxl,a[i][j]);
                }
            }
            int l=0,r=maxl;
            int mid;
            while(l<r)
            {
                int mid=(l+r)/2;
                if(check(mid))
                    r = mid;
                else
                    l = mid+1;
            }
            printf("%d
    ",l);
        }
    }
  • 相关阅读:
    BZOJ 1718: [Usaco2006 Jan] Redundant Paths 分离的路径( tarjan )
    BZOJ 1040: [ZJOI2008]骑士( 树形dp )
    BZOJ 1691: [Usaco2007 Dec]挑剔的美食家( 平衡树 )
    HDU 5667 Sequence 矩阵快速幂
    FZU 2225 小茗的魔法阵 扫描线+树状数组
    UVA 11916 Emoogle Grid 离散对数 大步小步算法
    UVA 11754 Code Feat 中国剩余定理+暴力
    FZU 2092 收集水晶 dp+bfs
    FZU2090 旅行社的烦恼 巧妙floyd 最短路
    UVA 11426 GCD
  • 原文地址:https://www.cnblogs.com/WWkkk/p/7412853.html
Copyright © 2020-2023  润新知