第K大也就是第n-K+1小,所以就可以的二分答案了 (江哥讲过一道类似题)
二分答案找出比当前答案小的数的位置的坐标,判断一下是否可以选出满足不在同一行同一列的n-K+1个数,然后就可以跑匈牙利了,对于一个坐标(x,y)如果满足a[x][y]≤a[x][y]当前答案,就把第x行向第y列连边,然后跑匈牙利判断最大匹配是否大于n-K+1
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<queue>
#include<set>
using
namespace
std;
#define M 300
#define N 1000001
struct
edge
{
int
v,next;
}e[N<<1];
int
head[N<<1];
int
cnt;
int
map[M][M];
int
ly[N],f[N];
int
n,m,k;
int
l,r;
int
maxn,tot,ans;
void
link(
int
x,
int
y)
{
e[++cnt]=(edge){y,head[x]};
head[x]=cnt;
}
bool
find(
int
d)
{
for
(
int
i=head[d];i;i=e[i].next)
{
int
t=e[i].v;
if
(ly[t]!=tot)
{
ly[t]=tot;
if
(!f[t] || find(f[t]))
{
f[t]=d;
return
true
;
}
}
}
return
false
;
}
int
work(
int
x)
{
ans=cnt=0;
memset
(head,0,
sizeof
(head));
memset
(f,0,
sizeof
(f));
for
(
int
i=1;i<=n;i++)
for
(
int
j=1;j<=m;j++)
if
(map[i][j]<=x)
link(i,j);
for
(
int
i=1;i<=n;i++)
{
tot++;
ans+=find(i);
}
return
ans>=k ? 1: 0;
}
int
main()
{
scanf
(
"%d%d%d"
,&n,&m,&k);
k=n-k+1;
for
(
int
i=1;i<=n;i++)
for
(
int
j=1;j<=m;j++)
scanf
(
"%d"
,&map[i][j]),maxn=max(maxn,map[i][j]);
l=1;
r=maxn;
while
(l<r)
{
int
m=l+r>>1;
if
(work(m))
r=m;
else
l=m+1;
}
printf
(
"%d\n"
,l);
return
0;
}