[二分][匈牙利算法] Bzoj P4443 小凸玩矩阵

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

Sample Output

3

HINT

 

1<=K<=N<=M<=250,1<=矩阵元素<=10^9

 

题解

  • 二分答案转化为判定性问题
  • 设二分的答案为mid,用二分图匹配来求最多能选出多少个不大于mid的数即可

代码

 1 #include <cstdio>
 2 #include <iostream>
 3 #include <cstring>
 4 using namespace std;
 5 int n,m,k,cnt,num,l,r,ans,a[260][260],head[100000],vis[260],p[260];
 6 struct edge {int to,from;}e[100000];
 7 void add(int x,int y) { e[++cnt].to=y,e[cnt].from=head[x],head[x]=cnt; }
 8 bool dfs(int x)
 9 {
10     for (int i=head[x];i;i=e[i].from)
11         if (!vis[e[i].to])
12         {
13             vis[e[i].to]=1;
14             if (!p[e[i].to]||dfs(p[e[i].to])) { p[e[i].to]=x; return 1; }
15         }
16     return 0; 
17 }
18 bool check(int x)
19 {
20     memset(head,0,sizeof(head)),cnt=num=0;
21     for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) if (a[i][j]<=x) add(i,j);    
22     memset(p,0,sizeof(p));
23     for (int i=1;i<=n;i++) 
24     {
25         memset(vis,0,sizeof(vis));
26         if (dfs(i)) num++;
27     }
28     return num>n-k;
29 }
30 int main()
31 {
32     scanf("%d%d%d",&n,&m,&k);
33     for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) scanf("%d",&a[i][j]),l=min(l,a[i][j]),r=max(r,a[i][j]);
34     while (l<=r)
35     {
36         int mid=l+r>>1;
37         if (check(mid)) ans=mid,r=mid-1; else l=mid+1;
38     }
39     printf("%d",ans);
40 }

 

posted @ 2019-07-09 15:30  BEYang_Z  阅读(192)  评论(0编辑  收藏  举报