【bzoj4443】[Scoi2015]小凸玩矩阵
第K大也就是第n-K+1小,所以就可以的二分答案了 (江哥讲过一道类似题)
二分答案找出比当前答案小的数的位置的坐标,判断一下是否可以选出满足不在同一行同一列的n-K+1个数,然后就可以跑匈牙利了,对于一个坐标(x,y)如果满足a[x][y]≤a[x][y]当前答案,就把第x行向第y列连边,然后跑匈牙利判断最大匹配是否大于n-K+1
1 2 3 #include<algorithm> 4 #include<iostream> 5 #include<cstdlib> 6 #include<cstring> 7 #include<cstdio> 8 #include<cmath> 9 #include<queue> 10 #include<set> 11 using namespace std; 12 13 #define M 300 14 #define N 1000001 15 16 struct edge 17 { 18 int v,next; 19 }e[N<<1]; 20 int head[N<<1]; 21 int cnt; 22 23 int map[M][M]; 24 int ly[N],f[N]; 25 26 int n,m,k; 27 int l,r; 28 int maxn,tot,ans; 29 30 void link(int x,int y) 31 { 32 e[++cnt]=(edge){y,head[x]}; 33 head[x]=cnt; 34 } 35 36 bool find(int d) 37 { 38 for (int i=head[d];i;i=e[i].next) 39 { 40 int t=e[i].v; 41 if (ly[t]!=tot) 42 { 43 ly[t]=tot; 44 if (!f[t] || find(f[t])) 45 { 46 f[t]=d; 47 return true; 48 } 49 } 50 } 51 return false; 52 } 53 54 int work(int x) 55 { 56 ans=cnt=0; 57 memset(head,0,sizeof(head)); 58 memset(f,0,sizeof(f)); 59 for (int i=1;i<=n;i++) 60 for (int j=1;j<=m;j++) 61 if (map[i][j]<=x) 62 link(i,j); 63 for (int i=1;i<=n;i++) 64 { 65 tot++; 66 ans+=find(i); 67 } 68 return ans>=k ? 1: 0; 69 } 70 71 int main() 72 { 73 scanf("%d%d%d",&n,&m,&k); 74 k=n-k+1; 75 for (int i=1;i<=n;i++) 76 for (int j=1;j<=m;j++) 77 scanf("%d",&map[i][j]),maxn=max(maxn,map[i][j]); 78 l=1; 79 r=maxn; 80 while (l<r) 81 { 82 int m=l+r>>1; 83 if (work(m)) 84 r=m; 85 else 86 l=m+1; 87 } 88 printf("%d\n",l); 89 return 0; 90 }