zoukankan      html  css  js  c++  java
  • BZOJ_4443_[Scoi2015]小凸玩矩阵_二分+二分图匹配

    BZOJ_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


    二分答案x,行列做点连边,把权值大于x的扔掉,判断最大匹配和K的关系。

    代码:

    #include <cstdio>
    #include <cstring>
    #include <queue>
    #define inf 0x7fffffff
    using namespace std;
    int n , m , k , a[260][260] , head[100000] , to[100000] , next[100000] , cnt , vis[260] , from[260];
    void add(int x , int y)
    {
        to[++cnt] = y , next[cnt] = head[x] , head[x] = cnt;
    }
    bool dfs(int x)
    {
        int i;
        for(i = head[x] ; i ; i = next[i])
        {
            if(!vis[to[i]])
            {
                vis[to[i]] = 1;
                if(!from[to[i]] || dfs(from[to[i]]))
                {
                    from[to[i]] = x;
                    return 1;
                }
            }
        }
        return 0;
    }
    bool judge(int mid)
    {
        int i , j , num = 0;
        memset(head , 0 , sizeof(head));
        cnt = 0;
        for(i = 1 ; i <= n ; i ++ )
            for(j = 1 ; j <= m ; j ++ )
                if(a[i][j] <= mid)
                    add(i , j);
        memset(from , 0 , sizeof(from));
        for(i = 1 ; i <= n ; i ++ )
        {
            memset(vis , 0 , sizeof(vis));
            if(dfs(i)) num ++ ;
        }
        return num > n - k;
    }
    int main()
    {
        int i , j , l = inf , r = 0 , mid , ans = 0;
        scanf("%d%d%d" , &n , &m , &k);
        for(i = 1 ; i <= n ; i ++ )
            for(j = 1 ; j <= m ; j ++ )
                scanf("%d" , &a[i][j]) , l = min(l , a[i][j]) , r = max(r , a[i][j]);
        while(l <= r)
        {
            mid = (l + r) >> 1;
            if(judge(mid)) ans = mid , r = mid - 1;
            else l = mid + 1;
        }
        printf("%d
    " , ans);
        return 0;
    }
    
  • 相关阅读:
    百度面试题:把数组排成最小的数
    面试题:在O(1)时间删除链表结点
    从第一字符串中删除第二个字符串中所有的字符
    在一个字符串中找到第一个只出现一次的字符
    大整数运算
    输出1到最大的N位数
    删除字符串中的数字并压缩字符串
    排列 或组合问题的解法(包含回溯法)
    卡特兰数(Catalan)简介
    编程之美-分层遍历二叉树
  • 原文地址:https://www.cnblogs.com/suika/p/8742692.html
Copyright © 2011-2022 走看看