bzoj4443: [Scoi2015]小凸玩矩阵

来源:互联网 发布:宿迁12345网络问政电话 编辑:程序博客网 时间:2024/05/18 13:41

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

题解:
看了讨论就发现是二分了,二分ans,判断如果小于ans的有n-k+1个那么ans可以变小。
我们可以用网络流来判断,建边如下:
ins(st,i,1),//表示起点向行连一条边
ins(j+n,ed,1),//表示列向终点连一条边
如果i,j这个点的值<=ansins(i,j+n,1)
限制流量为一,就保证了不会选到在同行或者同列的店
#include<cstdio>#include<cstdlib>#include<cstring>#include<algorithm>#define inf 0x7fffffff/3 using namespace std;const int N=600;int n,m,k;int map[N][N];int l,r=0,st,ed;struct node{int x,y,z,next,other;}sa[N*N];int len=0,first[N];void ins(int x,int y,int z){    len++;    sa[len].x=x;    sa[len].y=y;    sa[len].z=z;    sa[len].next=first[x];    first[x]=len;    sa[len].other=len+1;         len++;    sa[len].x=y;    sa[len].y=x;    sa[len].z=0;    sa[len].next=first[y];    first[y]=len;    sa[len].other=len-1;}int list[100005],h[100005],head,tail;bool bt()//宽搜只是为了构建h数组 {    memset(h,0,sizeof(h));h[st]=1; //出发点的层次为1    list[1]=st;head=1;tail=2; //宽搜    while(head!=tail)    {        int x=list[head];        for(int k=first[x];k!=-1;k=sa[k].next)        {            int y=sa[k].y;            if(  sa[k].z>0 &&  h[y]==0  )//a[k].c>0让多次构图成为可能            {                // x >y这条边还有流量,并且 y没有访问过                h[y]=h[x]+1;   //y作为x的下一层                list[tail++]=y;            }        }        head++;    }    if(h[ed]>0) return true;//如果最后能到ed返回true,否则返回false    else return false;}int findans(int x,int f)//函数值等于:带着“期待流量”f从x出发,最后得到的“实际流量”s。 {    if(x==ed) return f; //x如果是终点,那么当前所带的期待目标流量都可以完成     int s=0,t;    for(int k=first[x];k!=-1;k=sa[k].next) // 尝试通过所有孩子结点分散任务    {        int y=sa[k].y;          if( sa[k].z>0 && h[y]==(h[x]+1) && s<f )//a[k].c>0表示x->y这条边还有流量,且y是x的下一层,且“实际流量”<“期望流量”还没有满        {             s+=(  t=findans(  y  , min(sa[k].z,f-s)  )  ); //从y出发,而附带的“期望流量”是多少呢?;             sa[k].z-=t;sa[ sa[k].other ].z+=t; //及时修改边的流量,且同时增加反向边的流量        }    }    if(s==0)h[x]=0;//如果x出发没有流量,x从此不可走    return s;}bool check(int x){memset(first,-1,sizeof(first));len=0;for(int i=1;i<=n;i++)ins(st,i,1);for(int j=1;j<=m;j++)ins(j+n,ed,1);for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){if(map[i][j]<=x)ins(i,j+n,1);}}int ans=0;while(bt()!=false){ans+=findans(st,inf);}if(ans>=n-k+1) return true;else return false;}int main(){scanf("%d%d%d",&n,&m,&k);st=0;ed=n+m+1;for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){scanf("%d",&map[i][j]);r=max(map[i][j],r);}}l=0;int mid,an;while(l<r){mid=(l+r)>>1;if(check(mid)==true) r=mid,an=mid;else l=mid+1;}printf("%d\n",l);}



阅读全文
0 0