[LUOGU] P4251 [SCOI2015]小凸玩矩阵

行列看成点,格子看成边,二分一个边权,删去大于它的边,新图上的最大流>k则答案可以更优,小于k则调整左边界。

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
using namespace std;

inline int rd(){
    int ret=0,f=1;char c;
    while(c=getchar(),!isdigit(c))f=c=='-'?-1:1;
    while(isdigit(c))ret=ret*10+c-'0',c=getchar();
    return ret*f;
}

const int MAXN=256*256;
const int M=256*256*2;

struct Edge{
    int next,to,f;
}e[M<<1];
int ecnt=1,head[MAXN];
inline void add(int x,int y,int f){
    e[++ecnt].next = head[x];
    e[ecnt].to = y;
    e[ecnt].f = f;
    head[x] = ecnt;
}

int n,m,num;
int a[256][256];
int b[MAXN],p;

int dep[MAXN];
queue<int> Q;
bool bfs(int s,int t){
    memset(dep,0,sizeof(dep));
    dep[s]=1;Q.push(s);
    while(!Q.empty()){
        int top=Q.front();Q.pop();
        for(int i=head[top];i;i=e[i].next){
            int v=e[i].to;
            if(dep[v]||!e[i].f) continue;
            dep[v]=dep[top]+1;Q.push(v);
        }
    }
    return dep[t];
}
int cur[MAXN];
int dfs(int x,int flow,int t){
    if(x==t) return flow;
    int used=0,tmp;
    for(int i=head[x];i;i=e[i].next){
        int v=e[i].to;
        if(dep[v]!=dep[x]+1) continue;
        tmp=dfs(v,min(flow-used,e[i].f),t);
        e[i].f-=tmp;e[i^1].f+=tmp;used+=tmp;
        if(used==flow) return flow;
        if(e[i].f) cur[x]=i;
    }
    if(!used) dep[x]=-1;
    return used;
}
int dinic(int s,int t){
    int ret=0;
    while(bfs(s,t)){
        memcpy(cur,head,sizeof(head));
        ret+=dfs(s,1<<30,t);
    }
    return ret;
}

int main(){
    n=rd();m=rd();num=rd();
    int S=n*m+1,T=n*m+2; 
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            b[++p]=a[i][j]=rd();
        }
    }
    int ans=1<<30;
    sort(b+1,b+1+p);
    int l=1,r=p;
    while(l<=r){
        int mid=l+r>>1;
        ecnt=1;
        memset(head,0,sizeof(head));
        for(int i=1;i<=n;i++)add(S,i,1),add(i,S,0);
        for(int i=1;i<=m;i++)add(i+n,T,1),add(T,i+n,0);
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                if(a[i][j]>b[mid]) continue;
                add(i,j+n,1);
                add(j+n,i,0);
            }
        }
        int tmp=dinic(S,T);
        if(tmp>=n-num+1) r=mid-1,ans=b[mid];
        else l=mid+1;
    }
    cout<<ans;
    return 0;
}
未经许可,禁止搬运。
原文地址:https://www.cnblogs.com/ghostcai/p/9534833.html