题目:洛谷P4251、BZOJ4443。
题目大意:
有一个(n imes m(nleq m))的矩阵,要选出n个数,使得这n个数既不同行也不同列。问选的数中第k大的数最小可以是多少。
解题思路:
首先二分答案,然后只要判断,是否能选择至少n-k+1个数,它们的值都不超过当前的答案。
然后很简单,对每个小于等于当前答案的数,行向列连边。做二分图匹配即可。
时间复杂度(n^2log)级别。
C++ Code:
#include<cstdio> #include<cctype> #include<cstring> int n,m,k; inline int readint(){ int c=getchar(),d=0; for(;!isdigit(c);c=getchar()); for(;isdigit(c);c=getchar()) d=(d<<3)+(d<<1)+(c^'0'); return d; } int p[252][252],a[252][252],dy[252],vis[252]; int dfs(int u){ for(int i=1;i<=m;++i) if(p[u][i]&&!vis[i]){ vis[i]=1; if(!dy[i]||dfs(dy[i])){ dy[i]=u; return 1; } } return 0; } bool ok(int x){ for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) p[i][j]=a[i][j]<=x; memset(dy,0,sizeof dy); int ans=0; for(int i=1;i<=n;++i){ memset(vis,0,sizeof vis); ans+=dfs(i); } return ans>=n-k+1; } int main(){ n=readint(),m=readint(),k=readint(); for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) a[i][j]=readint(); int l=0,r=0x3f3f3f3f,ans=0x3f3f3f3f; while(l<=r){ int mid=l+r>>1; if(ok(mid))r=mid-1,ans=mid;else l=mid+1; } printf("%d ",ans); return 0; }