第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 1000001struct 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;}原文:http://www.cnblogs.com/yangjiyuan/p/5365658.html