4443: [Scoi2015]小凸玩矩阵
Description
小凸和小方是好朋友,小方给小凸一个N*M(N<=M)的矩阵A,要求小秃从其中选出N个数,其中任意两个数字不能在同一行或同一列,现小凸想知道选出来的N个数中第K大的数字的最小值是多少。
Input
第一行给出三个整数N,M,K
接下来N行,每行M个数字,用来描述这个矩阵
Output
如题
Sample Input
3 4 2
1 5 6 6
8 3 4 3
6 8 6 3
1 5 6 6
8 3 4 3
6 8 6 3
Sample Output
3
HINT
1<=K<=N<=M<=250,1<=矩阵元素<=10^9
题目大意:不多说了。。
解题思路:看到第k大的数的最小值这种东西首先想到二分,这题把二分和二分图结合在一起。。终于做出了一题不是模板的题。。接下来具体说说怎么二分。二分枚举k,然后每次都先清空边,遍历一遍边,把小于等于k的边加进去。然后套匈牙利模板就行。如果满足,r=mid(因为可能刚好是mid,所以不能是r=mid-1),不满足则是l=mid+1。
#include <cstdio> #include <algorithm> #include <cstring> using namespace std; const int maxn=255; bool line[maxn][maxn],used[maxn]; int a[maxn][maxn]; int girl[maxn],n,m,k; bool dfs(int x) { int i,j; for(j=1;j<=m;j++) { if(line[x][j]==true&&used[j]==false) { used[j]=true; if(girl[j]==0||dfs(girl[j])) { girl[j] = x; return true; } } } return false; } int cal() { int ans=0; memset(girl,0,sizeof(girl)); for(int i=1;i<=n;i++) { memset(used,false,sizeof(used)); if(dfs(i)) { ans++; } } return ans; } bool check(int mid) { memset(line,0,sizeof(line)); for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { if(a[i][j]<=mid) { line[i][j] = 1; } } } int ans=cal(); if(ans>=k) return true; else return false; } int main() { while(scanf("%d %d %d",&n,&m,&k)!=EOF) { k=n-k+1; memset(line,false,sizeof(line)); int x,y,maxl=1; for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { scanf("%d",&a[i][j]); maxl = max(maxl,a[i][j]); } } int l=0,r=maxl; int mid; while(l<r) { int mid=(l+r)/2; if(check(mid)) r = mid; else l = mid+1; } printf("%d\n",l); } }