版权声明:随意转载,愿意的话提一句作者就好了 https://blog.csdn.net/stone41123/article/details/84134317
Link
Diffculty
算法难度6,思维难度5,代码难度6
Description
给定一个 的矩阵,要求你每行选一个元素,同时不能有同列元素同时被选。
你要最小化这些元素中的第 大权值。
Solution
首先我们可以二分答案,这个非常显然。
二分答案之后你要判断是否存在合法方案,考虑网络流。
我们可以行列建点,因为每行每列都最多选一个,那么可以看做匹配。
这样我们直接跑最大流,就可以判断是否存在合法方案了。
判断合法方案也可以用匈牙利跑最大匹配,或许会更快。
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#define LL long long
using namespace std;
inline int read(){
int x=0,f=1;char ch=' ';
while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0' && ch<='9')x=x*10+(ch^48),ch=getchar();
return f==1?x:-x;
}
const int N=255,M=N*N*10;
int n,m,k,tot,a[N][N],s,t;
int head[M],to[M],Next[M],flow[M];
inline void addedge(int x,int y,int l){
to[++tot]=y;Next[tot]=head[x];head[x]=tot;flow[tot]=l;
to[++tot]=x;Next[tot]=head[y];head[y]=tot;flow[tot]=0;
}
int d[M],q[M],cur[M];
inline bool bfs(){
for(int i=s;i<=t;++i)d[i]=1e9;
int l=1,r=1;q[1]=s;d[s]=0;
while(l<=r){
int x=q[l++];
for(int i=head[x];~i;i=Next[i]){
int u=to[i];
if(flow[i] && d[u]>d[x]+1){
d[u]=d[x]+1;
q[++r]=u;
}
}
}
return d[t]!=1e9;
}
inline int dfs(int x,int a){
if(x==t || !a)return a;
int F=0,f;
for(int &i=cur[x];~i;i=Next[i]){
int u=to[i];
if(flow[i] && d[u]==d[x]+1 && (f=dfs(u,min(a,flow[i])))>0){
flow[i]-=f;
flow[i^1]+=f;
F+=f;
a-=f;
if(!a)return F;
}
}
return F;
}
inline int dinic(){
int F=0;
while(bfs()){
for(int i=s;i<=t;++i)cur[i]=head[i];
F+=dfs(s,1e9);
}
return F;
}
int main(){
n=read();m=read();k=read();
for(int i=1;i<=n;++i)for(int j=1;j<=m;++j)a[i][j]=read();
s=0;t=n+m+1;
int l=1,r=1e9,mid;
while(l<r){
mid=(l+r)>>1;
tot=-1;
for(int i=s;i<=t;++i)head[i]=-1;
for(int i=1;i<=n;++i)addedge(s,i,1);
for(int i=1;i<=m;++i)addedge(n+i,t,1);
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
if(a[i][j]<=mid)addedge(i,n+j,1);
for(int i=s;i<=t;++i)cur[i]=head[i];
if(dinic()>=n-k+1)r=mid;
else l=mid+1;
}
printf("%d\n",l);
return 0;
}