bzoj 4443: [Scoi2015]小凸玩矩阵

Posted CXCXCXC

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj 4443: [Scoi2015]小凸玩矩阵相关的知识,希望对你有一定的参考价值。

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 149  Solved: 81
[Submit][Status][Discuss]

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

题解:

  N个数中的第K大,就是第N-K+1小,这点要是没看见就毁了。设这个数为x,二分这个数,判断是否合法。

  判断合法的方法,N^2枚举矩阵中的每个数,如果这个a[i][j]数小于等于x,让i连一条到j,容量为1的边。因为要保证N个数的i,j各不相同,所以设行i为x集,列j为y集,所有边权均为1,做最大流,也就是二分图的最大匹配。如果跑出来的maxflow大于等于N-K+1,说明x满足条件。注意以上两个不等关系都是大于等于,因为要考虑这样一种情况,整个矩阵的数字都是1,第1小是1,第N小还是1。我被这个坑了好久。。。

  1 /**************************************************************
  2     Problem: 4443
  3     User: __abcdef__
  4     Language: C++
  5     Result: Accepted
  6     Time:216 ms
  7     Memory:14640 kb
  8 ****************************************************************/
  9  
 10 #include<iostream>
 11 #include<cstdio>
 12 #include<cstdlib>
 13 #include<cstring>
 14 #include<cmath>
 15 #include<algorithm>
 16 #include<queue>
 17 #include<vector>
 18 using namespace std;
 19 typedef long long LL;
 20 const int inf=1e9,maxn=300;
 21 int N,M,K,S,T,tot,MIN=inf,MAX;
 22 int a[maxn][maxn],tmp[maxn][maxn];
 23 struct MAT{
 24     int x,y,v,f;
 25 }mat[maxn*maxn];
 26 inline int cmp(const MAT & e,const MAT & w){
 27     return e.v<w.v;
 28 }
 29   
 30 struct Edge{
 31     int to,rest,next;
 32 }e[maxn*maxn*10];
 33 int head[maxn*maxn],cnt=1;
 34 inline void Addedge(int x,int y,int r){
 35     e[++cnt].to=y; e[cnt].rest=r; e[cnt].next=head[x]; head[x]=cnt;
 36     e[++cnt].to=x; e[cnt].rest=0; e[cnt].next=head[y]; head[y]=cnt;
 37 }
 38   
 39 int dis[maxn*maxn];
 40 inline bool BFS(){
 41     memset(dis,0,sizeof(dis));
 42     static queue<int> Q;
 43     while(!Q.empty()) Q.pop();
 44     Q.push(S); dis[S]=1;
 45     while(!Q.empty()){
 46         int x=Q.front(); Q.pop();
 47         for(int i=head[x];i;i=e[i].next){
 48             int y=e[i].to;
 49             if(dis[y]==0&&e[i].rest){
 50                 dis[y]=dis[x]+1;
 51                 Q.push(y);
 52             }
 53         }
 54     }
 55     if(dis[T]!=0) return true;
 56     return false;
 57 }
 58 inline int DFS(int x,int flow){
 59     if(x==T) return flow;
 60     int now=0,temp;
 61     for(int i=head[x];i;i=e[i].next){
 62         int y=e[i].to;
 63         if(dis[y]==dis[x]+1&&e[i].rest){
 64             temp=DFS(y,min(flow-now,e[i].rest));
 65             e[i].rest-=temp;
 66             e[i^1].rest+=temp;
 67             now+=temp;
 68             if(now==flow) return flow;
 69         }
 70     }
 71     if(!now) dis[x]=0;
 72     return now;
 73 }
 74   
 75 inline int dinic(){
 76     int ans=0;
 77     while(BFS()==true) ans+=DFS(S,inf);
 78     return ans;
 79 }
 80   
 81 inline bool jud(int x){
 82       
 83     for(int i=1;i<=cnt+10;i++) e[i].to=e[i].rest=e[i].next=0;
 84     memset(head,0,sizeof(head)); cnt=1;
 85     S=0; T=N+M+1;
 86     for(int i=1;i<=N;i++) Addedge(S,i,1);// S 连向 x集 权值为 1 
 87     for(int i=1;i<=M;i++) Addedge(N+i,T,1);//y集 连向 T 权值为 1 
 88     for(int i=1;i<=N;i++){// x集 连向 y集 
 89         for(int j=1;j<=M;j++){
 90             if(tmp[i][j]<=x){
 91                 Addedge(i,N+j,1);
 92             }
 93         }
 94     }
 95     int maxflow=dinic();
 96     if(maxflow>=N-K+1) return true;
 97     else return false;
 98 }
 99 inline int find(int l,int r){
100     if(l+1>=r){
101         if(jud(l)==true) return l;
102         else return r;
103     }
104     int mid=(l+r)>>1;
105     if(jud(mid)==true) return find(l,mid);
106     else return find(mid+1,r);
107 }
108 int main(){
109     scanf("%d%d%d",&N,&M,&K);
110     for(int i=1;i<=N;i++){
111         for(int j=1;j<=M;j++){
112             scanf("%d",&a[i][j]);
113             mat[++tot].x=i; mat[tot].y=j; mat[tot].v=a[i][j];
114         }
115     }
116     tot=0;
117     sort(mat+1,mat+N*M+1,cmp);
118     for(int i=1;i<=N*M;i++){
119         if(mat[i].v!=mat[i-1].v) mat[i].f=++tot;
120         else mat[i].f=tot;
121     }
122     for(int i=1;i<=N*M;i++){
123         tmp[mat[i].x][mat[i].y]=mat[i].f;
124         MIN=min(MIN,mat[i].f); MAX=max(MAX,mat[i].f);
125     }
126     int ggg=find(MIN,MAX);
127     for(int i=1;i<=N;i++){
128         for(int j=1;j<=M;j++){
129             if(tmp[i][j]==ggg){
130                 printf("%d\n",a[i][j]);
131                 return 0;
132             }
133         }
134     }
135     return 0;
136 }

 

以上是关于bzoj 4443: [Scoi2015]小凸玩矩阵的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ4443: [Scoi2015]小凸玩矩阵

BZOJ4443[Scoi2015]小凸玩矩阵 二分+二分图最大匹配

bzoj4443: [Scoi2015]小凸玩矩阵

bzoj4443[Scoi2015]小凸玩矩阵 二分+二分图匹配

BZOJ 4443 [Scoi2015]小凸玩矩阵(二分答案+二分图匹配)

[Scoi2015]小凸玩矩阵