二分图最大匹配
二分枚举第K大的数,满足的条件为选出的小于等于当前枚举到的数(num)的个数大于等于n-K+1。
判断方法就是对于每一个a[i][j]<=num建一条i到j的单向边,然后愉快的找增广路就可以啦。
AC代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct edge{
int next;
int to;
};
int a[255][255];
int h[255],who[255];
edge ed[200000];
bool f[255];
int n,m,k,mi=0x7fffffff,ma,K;
void create(int x,int y){
K++;
ed[K].next=h[x];
ed[K].to=y;
h[x]=K;
}
bool dfs(int x){
if (f[x]) return false;
f[x]=true;
for (int j=h[x];j;j=ed[j].next)
if (!who[ed[j].to]||dfs(who[ed[j].to])){
who[ed[j].to]=x;
return true;
}
return false;
}
bool pd(int num){
memset(h,0,sizeof(h));
K=0;
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
if (num>=a[i][j])
create(i,j);
int sum=0;
memset(who,0,sizeof(who));
for (int i=1;i<=n;i++){
memset(f,false,sizeof(f));
if (dfs(i))
sum++;
}
if (sum<k) return false;
return true;
}
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",&a[i][j]);
mi=min(mi,a[i][j]);
ma=max(ma,a[i][j]);
}
while (mi<=ma){
int mid=(mi+ma)/2;
if (pd(mid)) ma=mid-1;
else mi=mid+1;
}
printf("%d",mi);
return 0;
}