[SCOI2015]小凸玩矩阵
题目描述
小凸和小方是好朋友,小方给了小凸一个 n × m (的矩阵 A,并且要求小凸从矩阵中选出 nn 个数,其中任意两个数都不能在同一行或者同一列。现在小凸想知道,选出的 n 个数中第 k 大的数的最小值是多少。
输入格式
第 1 行读入 3 个整数 n, m, k。
接下来 nn 行,每一行有 m 个数字,第 i 行第 j 个数字代表矩阵中第 i 行第 j 列的元素Ai,j。
输出格式
输出包含一行,为选出的 n 个数中第 k 大数的最小值。
我们反过来想想
求第K大的最小值,就是说对第K大的数二分
就是在限制条件下,跑二分图
满足至少n-k+1个匹配的最小值
#include<bits/stdc++.h> #define re return #define inc(i,l,r) for(int i=l;i<=r;++i) using namespace std; template<typename T>inline void rd(T&x) { char c;bool f=0; while((c=getchar())<'0'||c>'9')if(c=='-')f=1; x=c^48; while((c=getchar())>='0'&&c<='9')x=x*10+(c^48); if(f)x=-x; } const int maxn=255; int match[maxn],n,m,k,K,hd[maxn],ans=2147483647; int a[maxn][maxn],vis[maxn],tot; inline bool dfs(int limit,int x) { inc(i,1,m) if(a[x][i]>limit||vis[i]==tot); else { vis[i]=tot; if(!match[i]||dfs(limit,match[i])) { match[i]=x; re 1; } } re 0; } inline int vivi(int x) { inc(j,1,m)vis[j]=match[j]=0; int cnt=0; inc(i,1,n) { ++tot; if(dfs(x,i))++cnt; inc(j,1,m)vis[j]=0; } re cnt; } int main() { int l=2147483647,r=0; rd(n),rd(m); rd(K); K=n-K+1; inc(i,1,n)inc(j,1,m) { rd(a[i][j]); l=min(l,a[i][j]); r=max(r,a[i][j]); } while(l<=r) { int mid=(l+r)>>1; if(vivi(mid)>=K)ans=mid,r=mid-1; else l=mid+1; } printf("%d",ans); re 0; }