题目:洛谷P4251、BZOJ4443。
题目大意:
有一个\(n\times m(n\leq m)\)的矩阵,要选出n个数,使得这n个数既不同行也不同列。问选的数中第k大的数最小可以是多少。
解题思路:
首先二分答案,然后只要判断,是否能选择至少n-k+1个数,它们的值都不超过当前的答案。
然后很简单,对每个小于等于当前答案的数,行向列连边。做二分图匹配即可。
时间复杂度\(n^2\log\)级别。
C++ Code:
#include<cstdio>
#include<cctype>
#include<cstring>
int n,m,k;
inline int readint(){
int c=getchar(),d=0;
for(;!isdigit(c);c=getchar());
for(;isdigit(c);c=getchar())
d=(d<<3)+(d<<1)+(c^'0');
return d;
}
int p[252][252],a[252][252],dy[252],vis[252];
int dfs(int u){
for(int i=1;i<=m;++i)
if(p[u][i]&&!vis[i]){
vis[i]=1;
if(!dy[i]||dfs(dy[i])){
dy[i]=u;
return 1;
}
}
return 0;
}
bool ok(int x){
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
p[i][j]=a[i][j]<=x;
memset(dy,0,sizeof dy);
int ans=0;
for(int i=1;i<=n;++i){
memset(vis,0,sizeof vis);
ans+=dfs(i);
}
return ans>=n-k+1;
}
int main(){
n=readint(),m=readint(),k=readint();
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
a[i][j]=readint();
int l=0,r=0x3f3f3f3f,ans=0x3f3f3f3f;
while(l<=r){
int mid=l+r>>1;
if(ok(mid))r=mid-1,ans=mid;else l=mid+1;
}
printf("%d\n",ans);
return 0;
}