[SCOI2015]小凸玩矩阵
小凸玩矩阵
题解
又一道二分图板子题
其实看到第
k
k
k大值最小应该很容易想到二分的。
我们可以先二分它的第
k
k
k大值,判断在当前二分的值下,只选不超过二分值的数是否可得到一种选
n
−
k
+
1
n-k+1
n−k+1个数的选法,如果可以,就一定有种方法使得第
k
k
k大值不超过当前的二分值。
至于判断当前可选的数是否可以选到
n
−
k
+
1
n-k+1
n−k+1个,可以通过二分图匹配来进行判断。
我们将行与列分成两组,也就是我们二分图的两边,在每个可选位置的行与列之间连边,跑最大匹配。
这样匹配出来的行和列一定是可选的。
源码
#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
#define MAXN 255
#define reg register
typedef long long LL;
template<typename _T>
inline void read(_T &x){
_T f=1;x=0;char s=getchar();
while('0'>s||'9'<s){if(s=='-')f=-1;s=getchar();}
while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
x*=f;
}
int n,m,k,a[MAXN][MAXN],idx,idy,head[MAXN],tot,cnt,p[MAXN],maxx;
bool vis[MAXN];
struct edge{int to,nxt;}e[MAXN*MAXN];
void addEdge(int u,int v){e[++tot]=(edge){v,head[u]};head[u]=tot;}
bool match(int x){
vis[x]=1;
for(int i=head[x];i;i=e[i].nxt)
if(p[e[i].to]==-1||(!vis[p[e[i].to]]&&match(p[e[i].to])))
return (p[e[i].to]=x,1);
return 0;
}
bool sakura(int mid){
for(int i=1;i<=n;i++)head[i]=0;tot=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(a[i][j]<=mid)addEdge(i,j);
for(int i=1;i<=m;i++)p[i]=-1;cnt=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++)vis[j]=0;
if(match(i))cnt++;
}
return cnt>=n-k+1;
}
signed main(){
read(n);read(m);read(k);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
read(a[i][j]),maxx=max(maxx,a[i][j]);
int l=1,r=maxx,ans=maxx;
while(l<=r){
int mid=l+r>>1;
if(sakura(mid))r=mid-1,ans=mid;
else l=mid+1;
}
printf("%d",ans);
return 0;
}

浙公网安备 33010602011771号