LibreOJ #2006. 「SCOI2015」小凸玩矩阵 二分答案+二分匹配
#2006. 「SCOI2015」小凸玩矩阵
内存限制:256 MiB时间限制:1000 ms标准输入输出
题目类型:传统评测方式:文本比较
上传者: 匿名
题目描述
小凸和小方是好朋友,小方给小凸一个 N×M N \times MN×M(N≤M N \leq MN≤M)的矩阵 A AA,要求小凸从其中选出 N NN 个数,其中任意两个数字不能在同一行或同一列,现小凸想知道选出来的 N NN 个数中第 K KK 大的数字的最小值是多少。
输入格式
第一行给出三个整数 N NN、M MM、K KK。
接下来 N NN 行,每行 M MM 个数字,用来描述这个矩阵。
输出格式
输出选出来的 N NN 个数中第 K KK 大的数字的最小值。
样例
样例输入
3 4 2
1 5 6 6
8 3 4 3
6 8 6 3
样例输出
3
数据范围与提示
1≤K≤N≤M≤250,1≤Ai,j≤109 1 \leq K \leq N \leq M \leq 250, 1 \leq A_{i, j} \leq 10 ^ 91≤K≤N≤M≤250,1≤Ai,j≤109
题目链接:https://loj.ac/problem/2006
题意:选出n个行列不相同的数,使得第k大最小。
思路:二分答案+二分匹配。二分答案,然后对行和列进行二分匹配,a[i][j]<=mid的最大匹配与n-k+1进行比较。
代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> #include<cstdio> #include<cmath> #include<cstring> #include<algorithm> #include<set> #include<queue> #include<stack> #include<map> #include<vector> using namespace std; typedef long long ll; typedef pair<int,int> P; const int maxn=300,maxm=1e5+100,inf=0x3f3f3f3f,mod=1e9+7; const ll INF=1e18+7; int n,m,k; ll a[maxn][maxn]; vector<int>G[maxn]; int match[maxn]; int used[maxn]; bool dfs(int u,ll mid) { for(int v=1; v<=m; v++) { if(a[u][v]>mid) continue; if(used[v]) continue; used[v]=true; if(match[v]<0||dfs(match[v],mid)) { match[v]=u; return true; } } return false; } bool check(ll mid) { int res=0; memset(match,-1,sizeof(match)); for(int i=1; i<=n; i++) { memset(used,false,sizeof(used)); res+=dfs(i,mid); } //cout<<res<<endl; return res>=n-k+1?1:0; } int main() { scanf("%d%d%d",&n,&m,&k); ll l=INF,r=0; for(int i=1; i<=n; i++) { ll mmin=INF,mmax=0; for(int j=1; j<=m; j++) { scanf("%d",&a[i][j]); l=min(l,a[i][j]),r=max(r,a[i][j]); } } ll ans=-1; while(l<=r) { ll mid=(l+r)/2; //cout<<l<<" "<<r<<" "<<mid<<endl; if(check(mid)) r=mid-1,ans=mid; else l=mid+1; } printf("%lld\n",ans); return 0; }
I am a slow walker,but I never walk backwards.