【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 }

 

posted @ 2016-04-07 21:54  Yangjiyuan  阅读(382)  评论(0编辑  收藏  举报