【题解】[SCOI2015]小凸玩矩阵
思路:题目要求变相解答一下,求出是否有n-k个数,不大于当前求的第k个数
而每一行每一列只能有一个数,就可以得到一个二分图的思路,边上的权值就是第i行第j列这个数的值
对于答案就是第k大的数,则用二分来求
每一次对mid进行判断时,要重建图,以满足要求
#include <cstdio> #include <iostream> #include <cctype> #include <algorithm> #include <cmath> #include <cstring> using namespace std; #define clr(x) memset(x,0,sizeof(x)) #define int long long inline int read(){ int s=0;bool flag=true;char ch=getchar(); while(!isdigit(ch)){if(ch=='-')flag=false;ch=getchar();} while(isdigit(ch)){s=(s<<3)+(s<<1)+ch-'0';ch=getchar();} return flag?s:-s; } inline void out_put(int x){ if(x<0) putchar('-'),x=-x; if(x>9) out_put(x/10); putchar(x%10+'0'); } inline void print(int x){out_put(x),puts("");} const int N=255; const int inf=0x3f3f3f3f3f3f3f3f3f; bool vis[N],line[N][N]; int row[N],w[N][N]; int n,m,k; inline bool find(int x){ for(int i=1;i<=m;i++) if(line[x][i] && !vis[i]){ vis[i]=true; if(!row[i] || find(row[i])){ row[i]=x; return true; } } return false; } inline void rebuild(int limit){ clr(line),clr(row); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if(w[i][j]<=limit) line[i][j]=true; } inline bool check(int x){ rebuild(x); int cnt=0; for(int i=1;i<=n;i++){ clr(vis); if(find(i)) cnt++; } if(cnt>n-k) return true; return false; } signed main(void){ n=read(),m=read(),k=read(); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) w[i][j]=read(); int l=1,r=inf,ans; while(l<=r){ int mid=(l+r)>>1; if(check(mid))r=mid-1,ans=mid; else l=mid+1; } print(ans); return 0; }