题目大意:从n*m矩阵中选出若干数,要求任意两个数字不能在同一行或同一列,求第k大数字的最小值
题解:显然需要二分答案x,判断是否可以取出至少n-k+1个数<=x
按照行列建出二分图,a[i][j]<=x就连边(i,j),跑二分图匹配
我的收获:~~~
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;
const int M=255;
const int INF=1e9;
int n,m,k;
int a[M][M],mp[M][M];
int lik[M];
bool vis[M];
void build(int limit)
{
memset(mp,0,sizeof(mp));
memset(lik,0,sizeof(lik));
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(a[i][j]<=limit) mp[i][j]=1;
}
int hungry(int x)
{
for(int i=1;i<=m;i++){
if(!mp[x][i]||vis[i]) continue;
vis[i]=1;
if(!lik[i]||hungry(lik[i])) return lik[i]=x;
}
return false;
}
bool check(int x)
{
build(x);
int ans=0;
for(int i=1;i<=n;i++){
memset(vis,0,sizeof(vis));
ans+=(bool)hungry(i);
}
return ans>=n-k+1;
}
void work()
{
int l,r,ans,mid;
for(l=1,r=INF;l<=r;){
mid=l+r>>1;
if(check(mid)) r=mid-1,ans=mid;
else l=mid+1;
}
cout<<ans<<endl;
}
void init()
{
cin>>n>>m>>k;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%d",&a[i][j]);
}
int main()
{
init();
work();
return 0;
}