【刷题】BZOJ 4443 [Scoi2015]小凸玩矩阵

时间:2023-03-08 20:56:10
【刷题】BZOJ 4443 [Scoi2015]小凸玩矩阵

Description

小凸和小方是好朋友,小方给小凸一个N*M(N<=M)的矩阵A,要求小秃从其中选出N个数,其中任意两个数字不能在同一行或同一列,现小凸想知道选出来的N个数中第K大的数字的最小值是多少。

Input

第一行给出三个整数N,M,K

接下来N行,每行M个数字,用来描述这个矩阵

Output

如题

Sample Input

3 4 2

1 5 6 6

8 3 4 3

6 8 6 3

Sample Output

3

HINT

1<=K<=N<=M<=250,1<=矩阵元素<=10^9

Solution

明显二分

二分答案后,判断是否可行

每一行每一列只能选一个数,经典套路,行列连边

小于等于答案的就可以选,行列连边,然后跑最大匹配

如果最大匹配小于 \(n-k+1\) ,那么说明二分的值小了,要变大

否则二分的值就可以减小,直到找到最小值

#include<bits/stdc++.h>
#define ui unsigned int
#define ll long long
#define db double
#define ld long double
#define ull unsigned long long
const int MAXN=500+10,MAXM=MAXN*MAXN+10,inf=0x3f3f3f3f;
int n,m,k,e=1,beg[MAXN],cur[MAXN],level[MAXN],vis[MAXN],clk,to[MAXM<<1],nex[MAXM<<1],cap[MAXM<<1],G[MAXN][MAXN],s,t;
std::queue<int> q;
template<typename T> inline void read(T &x)
{
T data=0,w=1;
char ch=0;
while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
if(ch=='-')w=-1,ch=getchar();
while(ch>='0'&&ch<='9')data=((T)data<<3)+((T)data<<1)+(ch^'0'),ch=getchar();
x=data*w;
}
template<typename T> inline void write(T x,char ch='\0')
{
if(x<0)putchar('-'),x=-x;
if(x>9)write(x/10);
putchar(x%10+'0');
if(ch!='\0')putchar(ch);
}
template<typename T> inline void chkmin(T &x,T y){x=(y<x?y:x);}
template<typename T> inline void chkmax(T &x,T y){x=(y>x?y:x);}
template<typename T> inline T min(T x,T y){return x<y?x:y;}
template<typename T> inline T max(T x,T y){return x>y?x:y;}
inline void insert(int x,int y,int z)
{
to[++e]=y;
nex[e]=beg[x];
beg[x]=e;
cap[e]=z;
to[++e]=x;
nex[e]=beg[y];
beg[y]=e;
cap[e]=0;
}
inline bool bfs()
{
memset(level,0,sizeof(level));
level[s]=1;
q.push(s);
while(!q.empty())
{
int x=q.front();
q.pop();
for(register int i=beg[x];i;i=nex[i])
if(cap[i]&&!level[to[i]])level[to[i]]=level[x]+1,q.push(to[i]);
}
return level[t];
}
inline int dfs(int x,int maxflow)
{
if(x==t||!maxflow)return maxflow;
vis[x]=clk;
int res=0;
for(register int &i=cur[x];i;i=nex[i])
if((vis[x]^vis[to[i]])&&cap[i]&&level[to[i]]==level[x]+1)
{
int f=dfs(to[i],min(cap[i],maxflow));
res+=f;
cap[i]-=f;
cap[i^1]+=f;
maxflow-=f;
if(!maxflow)break;
}
return res;
}
inline int Dinic()
{
int res=0;
while(bfs())clk++,memcpy(cur,beg,sizeof(cur)),res+=dfs(s,inf);
return res;
}
inline bool check(int num)
{
e=1;memset(beg,0,sizeof(beg));
for(register int i=1;i<=n;++i)insert(s,i,1);
for(register int i=1;i<=m;++i)insert(i+n,t,1);
for(register int i=1;i<=n;++i)
for(register int j=1;j<=m;++j)
if(G[i][j]<=num)insert(i,j+n,1);
if(Dinic()>=n-k+1)return true;
else return false;
}
int main()
{
int l=inf,r=-inf;
read(n);read(m);read(k);
s=n+m+1,t=s+1;
for(register int i=1;i<=n;++i)
for(register int j=1;j<=m;++j)read(G[i][j]),chkmax(r,G[i][j]),chkmin(l,G[i][j]);
int ans;
while(l<=r)
{
int mid=(l+r)>>1;
if(check(mid))ans=mid,r=mid-1;
else l=mid+1;
}
write(ans,'\n');
return 0;
}