• LibreOJ #2006. 「SCOI2015」小凸玩矩阵 二分答案+二分匹配


    #2006. 「SCOI2015」小凸玩矩阵

    内存限制:256 MiB时间限制:1000 ms标准输入输出
    题目类型:传统评测方式:文本比较
    上传者: 匿名

    题目描述

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

    输入格式

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

    输出格式

    输出选出来的 N NN 个数中第 K KK 大的数字的最小值。

    样例

    样例输入

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

    样例输出

    3

    数据范围与提示

    1≤K≤N≤M≤250,1≤Ai,j≤109 1 leq K leq N leq M leq 250, 1 leq A_{i, j} leq 10 ^ 91KNM250,1Ai,j​​109​​

    题目链接:https://loj.ac/problem/2006

    题意:选出n个行列不相同的数,使得第k大最小。

    思路:二分答案+二分匹配。二分答案,然后对行和列进行二分匹配,a[i][j]<=mid的最大匹配与n-k+1进行比较。

    代码:

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    #include<set>
    #include<queue>
    #include<stack>
    #include<map>
    #include<vector>
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> P;
    const int maxn=300,maxm=1e5+100,inf=0x3f3f3f3f,mod=1e9+7;
    const ll INF=1e18+7;
    int n,m,k;
    ll a[maxn][maxn];
    vector<int>G[maxn];
    int match[maxn];
    int used[maxn];
    bool dfs(int u,ll mid)
    {
        for(int v=1; v<=m; v++)
        {
            if(a[u][v]>mid) continue;
            if(used[v]) continue;
            used[v]=true;
            if(match[v]<0||dfs(match[v],mid))
            {
                match[v]=u;
                return true;
            }
        }
        return false;
    }
    bool check(ll mid)
    {
        int res=0;
        memset(match,-1,sizeof(match));
        for(int i=1; i<=n; i++)
        {
            memset(used,false,sizeof(used));
            res+=dfs(i,mid);
        }
        //cout<<res<<endl;
        return res>=n-k+1?1:0;
    }
    int main()
    {
        scanf("%d%d%d",&n,&m,&k);
        ll l=INF,r=0;
        for(int i=1; i<=n; i++)
        {
            ll mmin=INF,mmax=0;
            for(int j=1; j<=m; j++)
            {
                scanf("%d",&a[i][j]);
                l=min(l,a[i][j]),r=max(r,a[i][j]);
            }
        }
        ll ans=-1;
        while(l<=r)
        {
            ll mid=(l+r)/2;
            //cout<<l<<" "<<r<<" "<<mid<<endl;
            if(check(mid)) r=mid-1,ans=mid;
            else l=mid+1;
        }
        printf("%lld
    ",ans);
        return 0;
    }
    二分答案+二分比配
  • 相关阅读:
    Photoshop 基础七 位图 矢量图 栅格化
    Photoshop 基础六 图层
    Warfare And Logistics UVALive
    Walk Through the Forest UVA
    Airport Express UVA
    Guess UVALive
    Play on Words UVA
    The Necklace UVA
    Food Delivery ZOJ
    Brackets Sequence POJ
  • 原文地址:https://www.cnblogs.com/GeekZRF/p/7309238.html
Copyright © 2020-2023  润新知