BZOJ4443:[SCO2015]小凸玩矩阵
题目大意:给一个N*M的矩阵,选出N个数,使得每行没列只选一个数,求第K大的数的最小值是多少?
二分答案,第k大的数<=x,则有N-k+1个数<=k,用二分图判定。
#include<bits/stdc++.h> using namespace std; int n,m,k; int a[255][255]; void init(){ scanf("%d%d%d",&n,&m,&k); for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) scanf("%d",&a[i][j]); } struct node{ int to[100010],next[100010],h[300],tot; int g[500],tim,vis[500]; void init(){ tot=0; memset(h,0,sizeof(h)); memset(g,0,sizeof(g)); } void add(int x,int y){ tot++;to[tot]=y;next[tot]=h[x];h[x]=tot; } void build(int x){ init(); for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) if(a[i][j]<=x)add(i,j); } int find(int x){ for(int i=h[x];i;i=next[i]){ int v=to[i]; if(vis[v]==tim)continue; vis[v]=tim; if(!g[v]||find(g[v])){ g[v]=x; return 1; } } return 0; } int solve(){ int tmp=0; for(int i=1;i<=n;++i){ ++tim; if(find(i))tmp++; } return tmp; } }A; bool jud(int x){ A.build(x); int ans=A.solve(); return ans>=n-k+1; } void work(){ int L=1,R=1e9; while(L<R){ int mid=(L+R)>>1; if(jud(mid))R=mid; else L=mid+1; } printf("%d\n",L); } int main(){ init(); work(); return 0; }