bzoj 4443: [Scoi2015]小凸玩矩阵

4443: [Scoi2015]小凸玩矩阵

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

 
ACTY真大神!!!(大家有空去bzoj上搜搜看)
—————以下题解——————
很容易看出是二分答案。。
题目中说是第k大,其实是第n-k+1小(一直看错)。。。
我们每次验证mid时把矩阵中<=mid的数关于坐标连边,跑一遍二分图最大匹配,判断最大匹配数是否大于n-k+1。。
#include<stdio.h>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=255;
int n,m,k,i,j,ans,a[N][N],f[N],p[N];
int tot,head[N],Next[N*N],to[N*N];
void add(int x,int y)
{
    tot++;
    to[tot]=y;
    Next[tot]=head[x];
    head[x]=tot;
}
int dfs(int x,int T)
{
    int i;
    for(i=head[x];i!=-1;i=Next[i])
        if(p[to[i]]!=T)
    {
        int y=to[i];
        p[y]=T;
        if(f[y]==0||dfs(f[y],T))
        {
            f[y]=x;
            return 1;
        }
    }
    return 0;
}
int erfen(int l,int r)
{
    if(l>r) return l;
    int mid=(l+r)>>1,i,j,ans=0;
    tot=0;
    for(i=1;i<=n;i++)
        head[i]=-1;
    for(i=1;i<=m;i++)
        p[i]=f[i]=0;
    for(i=1;i<=n;i++)
     for(j=1;j<=m;j++)
     if(a[i][j]<=mid) add(i,j);
    for(i=1;i<=n;i++)
        ans+=dfs(i,i);
    if(ans>=n-k+1) return erfen(l,mid-1);else
    return erfen(mid+1,r);
}
int main()
{
    scanf("%d%d%d",&n,&m,&k);
    for(i=1;i<=n;i++)
     for(j=1;j<=m;j++)
    {
        scanf("%d",&a[i][j]);
        ans=max(ans,a[i][j]);
    }
    cout<<erfen(1,ans);
    return 0;
}

 

posted @ 2016-05-15 11:46  lwq12138  阅读(629)  评论(0编辑  收藏  举报