BZOJ 4443 小凸玩矩阵

二分+网络流。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
#include<algorithm>
#define maxn 255
#define maxv 10050
#define maxe 500500
#define inf 1000000007
using namespace std;
int n,m,k,g[maxv],nume=1,map[maxn][maxn],s,t;
int dis[maxv];
bool vis[maxv];
queue <int> q;
struct edge
{
    int v,f,nxt;
}e[maxe];
void addedge(int u,int v,int f)
{
    e[++nume].v=v;e[nume].f=f;e[nume].nxt=g[u];g[u]=nume;
    e[++nume].v=u;e[nume].f=0;e[nume].nxt=g[v];g[v]=nume;
}
bool bfs()
{
    while (!q.empty()) q.pop();
    for (int i=s;i<=t;i++) {dis[i]=inf;vis[i]=false;}
    dis[s]=0;vis[s]=true;q.push(s);
    while (!q.empty())
    {
        int head=q.front();q.pop();
        for (int i=g[head];i;i=e[i].nxt)
        {
            int v=e[i].v;
            if ((!vis[v]) && (e[i].f))
            {
                vis[v]=true;dis[v]=dis[head]+1;
                q.push(v);
            }
        }
    }
    if (!vis[t]) return false;
    return true;
}
int dinic(int x,int low)
{
    if (x==t) return low;
    int ret=0;
    for (int i=g[x];i && low;i=e[i].nxt)
    {
        int v=e[i].v;
        if ((dis[v]==dis[x]+1) && (e[i].f))
        {
            int dd=dinic(v,min(low,e[i].f));
            e[i].f-=dd;e[i^1].f+=dd;
            low-=dd;ret+=dd;
        }
    }
    if (!ret) dis[x]=inf;
    return ret;
}
bool check(int x)
{
    memset(g,0,sizeof(g));
    nume=1;
    for (int i=1;i<=n;i++) addedge(s,i,1);
    for (int i=1;i<=m;i++) addedge(i+n,t,1);
    for (int i=1;i<=n;i++)
        for (int j=1;j<=m;j++)
        {
            if (map[i][j]<=x)
                addedge(i,j+n,1);
        }
    int max_flow=0;
    while (bfs())
        max_flow+=dinic(s,inf);
    if (max_flow<n-k+1) return false;
    return true;
}
int half_search()
{
    int l=1,r=1000000000,ans;
    while (l<=r)
    {
        int mid=l+r>>1;
        if (check(mid)) {ans=mid;r=mid-1;}
        else l=mid+1;
    }
    return ans;
}
int main()
{
    scanf("%d%d%d",&n,&m,&k);
    s=0;t=n+m+1;
    for (int i=1;i<=n;i++)
        for (int j=1;j<=m;j++)
            scanf("%d",&map[i][j]);
    printf("%d\n",half_search());
    return 0;
}
时间: 2024-10-26 18:43:33

BZOJ 4443 小凸玩矩阵的相关文章

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&l

[Scoi2015]小凸玩矩阵

bzoj 4443: [Scoi2015]小凸玩矩阵 http://www.lydsy.com/JudgeOnline/problem.php?id=4443 Time Limit: 10 Sec  Memory Limit: 128 MB Description 小凸和小方是好朋友,小方给小凸一个N*M(N<=M)的矩阵A,要求小秃从其中选出N个数,其中任意两个数字不能在同一行或同一列,现小凸想知道选出来的N个数中第K大的数字的最小值是多少. Input 第一行给出三个整数N,M,K 接下来N

LibreOJ #2006. 「SCOI2015」小凸玩矩阵

二次联通门 : LibreOJ #2006. 「SCOI2015」小凸玩矩阵 /* LibreOJ #2006. 「SCOI2015」小凸玩矩阵 本来以为是道数据结构题 后来想了想发现不可做 就考虑二分dp判断 推方程推不出来 就考虑用网络流判断了 二分出一个数 将小于这个数的位置的点编号 每行的可行点与下一行可行的点连边 后一边最大流判断可选出的数的个数是否符合要求即可 */ #include <cstdio> #include <iostream> #include <q

LibreOJ #2006. 「SCOI2015」小凸玩矩阵 二分答案+二分匹配

#2006. 「SCOI2015」小凸玩矩阵 内存限制:256 MiB时间限制:1000 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: 匿名 提交提交记录统计讨论测试数据 题目描述 小凸和小方是好朋友,小方给小凸一个 N×M N \times MN×M(N≤M N \leq MN≤M)的矩阵 A AA,要求小凸从其中选出 N NN 个数,其中任意两个数字不能在同一行或同一列,现小凸想知道选出来的 N NN 个数中第 K KK 大的数字的最小值是多少. 输入格式 第一行给出三个整数

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

[BZOJ4443][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<

bzoj 4443: [Scoi2015]小凸玩矩阵

Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 149  Solved: 81[Submit][Status][Discuss] Description 小凸和小方是好朋友,小方给小凸一个N*M(N<=M)的矩阵A,要求小秃从其中选出N个数,其中任意两个数字不能在同一行或同一列,现小凸想知道选出来的N个数中第K大的数字的最小值是多少. Input 第一行给出三个整数N,M,K 接下来N行,每行M个数字,用来描述这个矩阵 Output 如题 Samp

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

题目描述 小凸和小方是好朋友,小方给小凸一个N*M(N<=M)的矩阵A,要求小秃从其中选出N个数,其中任意两个数字不能在同一行或同一列,现小凸想知道选出来的N个数中第K大的数字的最小值是多少. 输入 第一行给出三个整数N,M,K 接下来N行,每行M个数字,用来描述这个矩阵 输出 如题 样例输入 3 4 2 1 5 6 6 8 3 4 3 6 8 6 3 样例输出 3 题解 二分+二分图最大匹配 最(第k)大值最小,很容易想到二分答案. 二分一个mid,若满足条件,一定满足:可以选出n-k+1个不

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

[题目链接]http://www.lydsy.com/JudgeOnline/problem.php?id=4443 [题目大意] 从矩阵中选出N个数,其中任意两个数字不能在同一行或同一列 求选出来的N个数中第K大的数字的最小值是多少. [题解] 我们二分这个第k大数字的大小,将其以上的数字全部删除, 在剩余的部分按行列连边,如果二分图匹配的数量大于n-k那么说明该答案可行. [代码] #include <cstdio> #include <algorithm> #include

BZOJ 4443: 小凸玩矩阵【二分图】

我是传送门 先看题目,从数列中选第K小,很容易想到二分或者单调队列,但这里单调队列显得不是那么合适.而任意两个数不在一行一列,这符合二分图的定义,所以思路就很明了了,找出所有的值然后去二分找答案. #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define oo 0x7f7f7f7f #define get(x) scanf( "%d&q