行列看成点,格子看成边,二分一个边权,删去大于它的边,新图上的最大流>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; }