【BZOJ4443】【SCOI2015】—小凸玩矩阵(二分+最大匹配)
简单题
考虑二分转化成判断性问题
既然总共能选且只能选个
那也就变成了能否选出个比他小的元素
跑最大匹配就完了
#include<bits/stdc++.h>
using namespace std;
#define ll long long
inline int read(){
char ch=getchar();
int res=0,f=1;
while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=getchar();
return res*f;
}
const int N=300;
const int M=100005;
const int inf=1e9;
int str,des,adj[M],nxt[M<<1],to[M<<1],cap[M<<1],lev[M],tp[M],cnt=1,n,m,k,num;
inline void addedge(int u,int v,int w){
nxt[++cnt]=adj[u],adj[u]=cnt,to[cnt]=v,cap[cnt]=w;
nxt[++cnt]=adj[v],adj[v]=cnt,to[cnt]=u,cap[cnt]=0;
}
struct node{
int x,y,val;
friend inline bool operator <(const node &a,const node &b){
return a.val<b.val;
}
}p[M];
inline bool bfs(){
memset(lev,-1,sizeof(lev));
queue<int> q;
lev[str]=0,q.push(str);
while(!q.empty()){
int u=q.front();q.pop();
for(int e=adj[u];e;e=nxt[e]){
int v=to[e];
if(cap[e]>0&&lev[v]==-1){
lev[v]=lev[u]+1,q.push(v);
if(v==des)return true;
}
}
}
return false;
}
int dfs(int u,int flow){
if(u==des)return flow;
int res=0;
for(int &e=tp[u];e;e=nxt[e]){
int v=to[e];
if(cap[e]>0&&lev[v]==lev[u]+1){
int now=dfs(v,min(cap[e],flow-res));
res+=now,cap[e]-=now,cap[e^1]+=now;
if(flow==res)break;
}
}
return res;
}
inline int dinic(){
int res=0;
while(bfs()){
memcpy(tp,adj,sizeof(adj));
res+=dfs(str,inf);
}
return res;
}
inline int check(int k){
memset(adj,0,sizeof(adj)),cnt=1;
for(int i=1;i<=n;i++)addedge(str,i,1);
for(int i=1;i<=m;i++)addedge(n+i,des,1);
for(int i=1;i<=num&&p[i].val<=k;i++){
addedge(p[i].y,p[i].x+n,1);
}
return dinic();
}
int main(){
n=read(),m=read(),k=read();
str=n+m+1,des=str+1;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++)
p[++num].val=read(),p[num].y=i,p[num].x=j;
}
sort(p+1,p+num+1);
int l=0,r=inf,ans=0,z;
while(l<=r){
int mid=(l+r)>>1;
if((z=check(mid))>=n-k+1)r=mid-1,ans=mid;
else l=mid+1;
}
cout<<ans;
}