• 题解 【SCOI2015】小凸玩矩阵


    题面

    解析

    这题其实也是网络流建图。。

    首先,转换下思路,

    求第k大的数的最小值,

    其实就是求一个最小的值,

    使选取的点中能有(n-k+1)个的值比它小。

    因此,可以采用二分答案,

    每次判断一个值,

    将比它小的点加到图中跑最大流,

    看流量是否大于(n-k+1)。

    那么,怎么连边呢?

    其实,我们可以每一行连源点,流量为1,

    每一列连汇点,流量为1,

    中间源点与汇点连INF。

    最后判断就能AC了!

    上AC代码:

    #include<bits/stdc++.h>
    using namespace std;
    
    inline int read(){
        int sum=0,f=1;char ch=getchar();
        while(ch>'9' || ch<'0'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0' && ch<='9'){sum=sum*10+ch-'0';ch=getchar();}
        return f*sum;
    }
    
    const int INF=0x3f3f3f3f;
    struct node{
        int next,to,v;
    }e[1000001];
    int n,k,m,ans,s,t;
    int a[1001][1001];
    int maxn=0;
    int head[100001],cnt;
    int d[100001],cur[100001];
    
    void add(int x,int y,int v){
        e[++cnt].to=head[x];e[cnt].next=y;
        e[cnt].v=v;head[x]=cnt;
        e[++cnt].to=head[y];e[cnt].next=x;
        e[cnt].v=0;head[y]=cnt;    
    }
    
    bool bfs(){    
        memset(d,0,sizeof(d));
        memcpy(cur,head,sizeof(cur));
        queue <int>    que;
        que.push(s);
        d[s]=1;
        while(!que.empty()){
            int x=que.front();
            que.pop();
            for(int i=head[x];i;i=e[i].to){
                int k=e[i].next;
                if(!e[i].v||d[k]) continue;
                d[k]=d[x]+1;
                que.push(k);
            }
        }
        return d[t];
    }
    
    int dfs(int x,int mi){
        if(x==t||!mi) return mi;
        int flow=0;
        for(int &i=cur[x];i;i=e[i].to){
            int k=e[i].next;
            if(!e[i].v||d[k]!=d[x]+1) continue;
            int ret=dfs(k,min(mi,e[i].v));
            flow+=ret;mi-=ret;
            e[i].v-=ret;e[i^1].v+=ret;
            if(!mi) break;
        }
        if(mi) d[x]=-1;
        return flow;
    }
    
    bool DINIC(int x){
        int ans=0;
        while(bfs()){
            ans+=dfs(s,INF);
        }
        if(ans>=n-k+1) return 1;
        return 0;
    }
    
    bool check(int x){
        memset(e,0,sizeof(e));
        memset(head,0,sizeof(head));
        cnt=1;
        for(int i=1;i<=n;i++) add(s,i,1);
        for(int j=1;j<=m;j++) add(j+n,t,1);
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                if(a[i][j]<=x) add(i,j+n,INF);
            }
        }
        if(DINIC(x)) return 1;
        return 0;
    }
    
    int main(){
        //freopen("matrix.in","r",stdin);
        //freopen("matrix.out","w",stdout);
        n=read();m=read();k=read();
        s=m+n+1;t=s+1;
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                a[i][j]=read();
                maxn=max(maxn,a[i][j]);
            }
        }
        int l=1,r=maxn;
        while(l<=r){
            int mid=(l+r)>>1;
            if(check(mid)){
                r=mid-1;ans=mid;
            }
            else l=mid+1;
        }
        printf("%d
    ",ans);
        return 0;
    }
  • 相关阅读:
    SimpleAdapter的用法
    ListView中加载大量的图片
    用PreferenceActivity做一个标准的设置界面
    用代码构造PreferenceScreen
    工具类之Condition
    工具类之Mutex
    Linux初探之如何查看帮助文档自学命令[网址]
    linux基础之帮助文档---常用的命令[转载]
    Linux 下常见的四款chm查看器比较[转载+亲测可用]
    Linux(Ubuntu)下MySQL的安装与配置[转载+亲测]
  • 原文地址:https://www.cnblogs.com/zsq259/p/10561805.html
Copyright © 2020-2023  润新知