zoukankan      html  css  js  c++  java
  • 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
    ",a[i][j]);
    131                 return 0;
    132             }
    133         }
    134     }
    135     return 0;
    136 }
  • 相关阅读:
    LeetCode-494. Target Sum(DFS&DP)
    页面过渡 页面切换
    推荐几款制作网页滚动动画的 JavaScript 库
    Loda Button
    在百度地图或谷歌地图给中国各省着色并高亮显示
    TweenMax.js
    anime.js 简单入门教程
    用nrm一键切换npm源
    阿里巴巴26个前端开源项目
    Git使用教程,最详细,最傻瓜,最浅显,真正手把手教
  • 原文地址:https://www.cnblogs.com/CXCXCXC/p/5310443.html
Copyright © 2011-2022 走看看