洛谷传送门
解析:
并不知道这道题为什么在洛谷上是紫题,感觉好水啊。
思路:
把行和列分别当做两部分图,中间连边,可以发现这是一个二分图匹配。
既然要求 k k k大值最小,显然想到二分。那就是第 n − k + 1 n-k+1 n−k+1小值最小。
每次二分出一个答案,将所有比它小的边全部激活,然后匈牙利找最大匹配,看最后的最大匹配数,如果 ≤ n − k + 1 \leq n-k+1 ≤n−k+1,则答案过小,下界上移,否则上界下移。
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const
inline int getint(){
re int num;
re char c;
while(!isdigit(c=gc()));num=c^48;
while(isdigit(c=gc()))num=(num<<1)+(num<<3)+(c^48);
return num;
}
cs int N=251;
bool g[N][N];
int a[N][N];
int match[N],vis[N],idx;
int n,m,k;
inline int find(int u){
for(int re v=1;v<=m;++v){
if((vis[v]^idx)&&g[u][v]){
vis[v]=idx;
if(!match[v]||find(match[v])){
match[v]=u;
return true;
}
}
}
return false;
}
inline bool check(int x){
memset(match,0,sizeof match);
for(int re i=1;i<=n;++i)
for(int re j=1;j<=m;++j)g[i][j]=a[i][j]<=x;
++idx;
int cnt=0;
for(int re i=1;i<=n;++i,++idx)if(find(i))++cnt;
return cnt>=n-k+1;
}
int minn=0x3f3f3f3f,maxn=0;
signed main(){
n=getint();
m=getint();
k=getint();
for(int re i=1;i<=n;++i)
for(int re j=1;j<=m;++j){
a[i][j]=getint();
maxn=max(maxn,a[i][j]);
minn=min(minn,a[i][j]);
}
int l=minn,r=maxn;
while(l<r){
int mid=(l+r)>>1;
if(check(mid))r=mid;
else l=mid+1;
}
cout<<l;
return 0;
}