背景:
GDOI2018考完了,凉凉......
看到了差距。
题目传送门:https://www.luogu.org/problemnew/show/P4251
题意:
有一个n*m的矩阵,选k个数,这n个数两两必须不在同一行和同一列,求第k大的数的最小值是多少。
思路:
通过“最大值最小”可以显然想到二分。
然后就按照套路跑网络流,看看是否可行。
套路:请见我的blog:luogu P1129 [ZJOI2007]矩阵游戏
代码:
#include<cstdio> #include<cstring> #include<queue> #include<algorithm> #define INF 2147483647 using namespace std; queue<int> f; struct node{int x,y,z,next;} a[200000]; int last[600],b[300][300]; int n,m,k,len,st,ed,ans; void ins(int x,int y,int z) { a[++len].x=x;a[len].y=y;a[len].z=z;a[len].next=last[x];last[x]=len; } int h[600]; bool bfs() { memset(h,0,sizeof(h)); h[st]=1; f.push(st); while(!f.empty()) { int x=f.front(); for(int i=last[x];i>=0;i=a[i].next) { int y=a[i].y; if(a[i].z>0&&h[y]==0) { h[y]=h[x]+1; f.push(y); } } f.pop(); } if(h[ed]) return true; else return false; } int dfs(int x,int f) { int s=0,t; if(x==ed) return f; for(int i=last[x];i>=0;i=a[i].next) { int y=a[i].y; if(a[i].z>0&&h[y]==h[x]+1&&f>s) { s+=(t=(dfs(y,min(f-s,a[i].z)))); a[i].z-=t; a[i^1].z+=t; } } if(!s) h[x]=0; return s; } int dinic() { int sum=0; while(bfs()) sum+=dfs(st,INF); return sum; } bool check(int x) { len=-1; memset(last,-1,sizeof(last)); for(int i=1;i<=n;i++) ins(st,i,1),ins(i,st,0); for(int i=1;i<=m;i++) ins(i+n,ed,1),ins(ed,i+n,0); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if(b[i][j]<=x) ins(i,j+n,1),ins(j+n,i,0); return dinic()>=n-k+1; } int main() { int l=INF,r=0,mid; scanf("%d %d %d",&n,&m,&k); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { scanf("%d",&b[i][j]); l=min(l,b[i][j]); r=max(r,b[i][j]); } st=0,ed=n+m+1; while(l<=r) { mid=(l+r)>>1; if(check(mid)) r=mid-1,ans=mid; else l=mid+1; } printf("%d",ans); }