[SCOI2015]小凸玩矩阵
题目:洛谷P4251、BZOJ4443。
题目大意:
有一个n×m(n≤m)的矩阵,要选出n个数,使得这n个数既不同行也不同列。问选的数中第k大的数最小可以是多少。
解题思路:
首先二分答案,然后只要判断,是否能选择至少n-k+1个数,它们的值都不超过当前的答案。
然后很简单,对每个小于等于当前答案的数,行向列连边。做二分图匹配即可。
时间复杂度n2log级别。
C++ Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | #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\n" ,ans); return 0; } |
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步