码迷,mamicode.com
首页 > 其他好文 > 详细

【bzoj4443】[Scoi2015]小凸玩矩阵

时间:2016-04-07 22:05:49      阅读:200      评论:0      收藏:0      [点我收藏+]

标签:

第K大也就是第n-K+1小,所以就可以的二分答案了 (江哥讲过一道类似题)

二分答案找出比当前答案小的数的位置的坐标,判断一下是否可以选出满足不在同一行同一列的n-K+1个数,然后就可以跑匈牙利了,对于一个坐标(x,y)如果满足a[x][y]≤a[x][y]当前答案,就把第x行向第y列连边,然后跑匈牙利判断最大匹配是否大于n-K+1

 

 

#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<queue>
#include<set>
using namespace std;
 
#define M 300
#define N 1000001
 
struct edge
{
    int v,next;
}e[N<<1];
int head[N<<1];
int cnt;
 
int map[M][M];
int ly[N],f[N];
 
int n,m,k;
int l,r;
int maxn,tot,ans;
 
void link(int x,int y)
{
    e[++cnt]=(edge){y,head[x]};
    head[x]=cnt;
}
 
bool find(int d)
{
    for (int i=head[d];i;i=e[i].next)
    {
        int t=e[i].v;
        if (ly[t]!=tot)
        {
            ly[t]=tot;
            if (!f[t] || find(f[t]))
            {
                f[t]=d;
                return true;
            }
        }
    }
    return false;
}
 
int work(int x)
{
    ans=cnt=0;
    memset(head,0,sizeof(head));
    memset(f,0,sizeof(f));
    for (int i=1;i<=n;i++)
        for (int j=1;j<=m;j++)
            if (map[i][j]<=x)
                link(i,j);
    for (int i=1;i<=n;i++)
    {
        tot++;
        ans+=find(i);
    }
    return ans>=k ? 1: 0;
}
 
int main()
{
    scanf("%d%d%d",&n,&m,&k);
    k=n-k+1;
    for (int i=1;i<=n;i++)
        for (int j=1;j<=m;j++)
            scanf("%d",&map[i][j]),maxn=max(maxn,map[i][j]);
    l=1;
    r=maxn;
    while (l<r)
    {
        int m=l+r>>1;
        if (work(m))
            r=m;
        else
            l=m+1;
    }
    printf("%d\n",l);
    return 0;
}

【bzoj4443】[Scoi2015]小凸玩矩阵

标签:

原文地址:http://www.cnblogs.com/yangjiyuan/p/5365658.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!