zoukankan      html  css  js  c++  java
  • 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;
    }
    二分答案+二分比配
  • 相关阅读:
    Qt之json解析
    ListView
    JAVA的文件操作【转】
    可以随着SeekBar滑块滑动显示的Demo
    Android 之Buletooth
    VC++之运算符重载简单小结
    Android之Audio和Video
    Android之内容提供者ContentProvider的总结
    Android之Intent
    Android之Activity小结
  • 原文地址:https://www.cnblogs.com/GeekZRF/p/7309238.html
Copyright © 2011-2022 走看看