[SCOI2015]小凸玩矩阵

题目:洛谷P4251、BZOJ4443。

题目大意:
有一个\(n\times m(n\leq m)\)的矩阵,要选出n个数,使得这n个数既不同行也不同列。问选的数中第k大的数最小可以是多少。
解题思路:
首先二分答案,然后只要判断,是否能选择至少n-k+1个数,它们的值都不超过当前的答案。
然后很简单,对每个小于等于当前答案的数,行向列连边。做二分图匹配即可。
时间复杂度\(n^2\log\)级别。

C++ Code:

#include<cstdio>
#include<cctype>
#include<cstring>
int n,m,k;
inline int readint(){
    int c=getchar(),d=0;
    for(;!isdigit(c);c=getchar());
    for(;isdigit(c);c=getchar())
    d=(d<<3)+(d<<1)+(c^'0');
    return d;
}
int p[252][252],a[252][252],dy[252],vis[252];
int dfs(int u){
    for(int i=1;i<=m;++i)
    if(p[u][i]&&!vis[i]){
        vis[i]=1;
        if(!dy[i]||dfs(dy[i])){
            dy[i]=u;
            return 1;
        }
    }
    return 0;
}
bool ok(int x){
    for(int i=1;i<=n;++i)
    for(int j=1;j<=m;++j)
    p[i][j]=a[i][j]<=x;
    memset(dy,0,sizeof dy);
    int ans=0;
    for(int i=1;i<=n;++i){
        memset(vis,0,sizeof vis);
        ans+=dfs(i);
    }
    return ans>=n-k+1;
}
int main(){
    n=readint(),m=readint(),k=readint();
    for(int i=1;i<=n;++i)
    for(int j=1;j<=m;++j)
    a[i][j]=readint();
    int l=0,r=0x3f3f3f3f,ans=0x3f3f3f3f;
    while(l<=r){
        int mid=l+r>>1;
        if(ok(mid))r=mid-1,ans=mid;else l=mid+1;
    }
    printf("%d\n",ans);
    return 0;
}

 

posted @ 2018-07-10 13:13  Mrsrz  阅读(184)  评论(0编辑  收藏  举报