zoukankan      html  css  js  c++  java
  • 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);
        }
    }
  • 相关阅读:
    使用ssh公钥实现ssh免密码登录
    如何定义领域模型(概念模型)
    17.python字符编码检测——chardet
    21.python对象的浅拷贝和深拷贝
    15.序列化python对象
    18.python的打包和发布
    16.python的网络编程
    13.python的文件操作
    linux下python、django框架的配置
    14.python的xml操作
  • 原文地址:https://www.cnblogs.com/WWkkk/p/7412853.html
Copyright © 2011-2022 走看看