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

二次联通门 : LibreOJ #2006. 「SCOI2015」小凸玩矩阵

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

    本来以为是道数据结构题
    后来想了想发现不可做

    就考虑二分dp判断
    推方程推不出来
    就考虑用网络流判断了

    二分出一个数
    将小于这个数的位置的点编号
    每行的可行点与下一行可行的点连边

    后一边最大流判断可选出的数的个数是否符合要求即可
*/
#include <cstdio>
#include <iostream>
#include <queue>
#include <cstring>

const int BUF = 10000102;
char Buf[BUF], *buf = Buf;

void read (int &now)
{
    for (now = 0; !isdigit (*buf); ++ buf);
    for (; isdigit (*buf); now = now * 10 + *buf - ‘0‘, ++ buf);
}

#define Max 301
#define INF 1e9

int S, T;
int number[Max][Max];
int N, M, K;

inline int min (int a, int b)
{
    return a < b ? a : b;
}
struct Edge
{
    int to, next, flow;
};

class Net_Flow
{
    private :

         Edge e[Max * Max * 20];
         int C, list[Max * Max * 2], _tech[Max * Max * 2];

         int deep[Max * Max * 2];

    public :

         inline void In (int u, int v, int flow)
         {
             e[++ C].to = v, e[C].next = list[u];
             e[C].flow = flow, list[u] = C;
             e[++ C].to = u, e[C].next = list[v];
             e[C].flow = 0, list[v] = C;
         }

         bool Bfs ()
         {
             std :: queue <int> Queue;
             Queue.push (S);
             memset (deep, -1, sizeof deep);
             int now, i;
             for (deep[S] = 0; !Queue.empty (); Queue.pop ())
             {
                 now = Queue.front ();
                 for (i = list[now]; i; i = e[i].next)
                     if (deep[e[i].to] < 0 && e[i].flow)
                     {
                         deep[e[i].to] = deep[now] + 1;
                         if (e[i].to == T)
                             return true;
                         Queue.push (e[i].to);
                     }
             }
             return deep[T] >= 0;
         }

         int Flowing (int now, int Flow)
         {
             if (now == T || !Flow)
                 return Flow;
             int res = 0, pos;
             for (int &i = _tech[now]; i; i = e[i].next)
             {
                 if (e[i].flow < 0 || deep[e[i].to] != deep[now] + 1)
                     continue;
                 pos = Flowing (e[i].to, min (e[i].flow, Flow));
                 if (pos > 0)
                 {
                     e[i].flow -= pos;
                    res += pos;
                    Flow -= pos;
                    e[i ^ 1].flow += pos;
                    if (Flow == 0)
                        break;
                 }
             }
             if (res != Flow)
                 deep[now] = -1;
             return res;
         }

         int Dinic ()
         {
              int Answer = 0;
               for (; Bfs (); )
             {
                for (int i = 0; i <= T; ++ i)
                    _tech[i] = list[i];
                 Answer += Flowing (S, INF);
              }
              return Answer;
         }

         inline void Clear ()
         {
             C = 1;
             for (int i = 0; i <= T; i ++)
                 list[i] = 0;
         }
};

Net_Flow Flow;

bool Check (int key)
{
    Flow.Clear ();
    int i, j;
    for (i = 1; i <= N; ++ i)
        Flow.In (S, i, 1);

    for (i = 1; i <= M; ++ i)
        Flow.In (i + N, T, 1);

    for (i = 1; i <= N; ++ i)
        for (j = 1; j <= M; ++ j)
            if (number[i][j] <= key)
            {
                Flow.In (i, i * M + j - M, INF);
                Flow.In (i * M + j - M, j + N, INF);
            }

    return Flow.Dinic () >= K;
}

inline int max (int a, int b)
{
    return a > b ? a : b;
}
int Main ()
{
    fread (buf, 1, BUF, stdin);

    read (N);
    read (M);
    read (K);

    K = N - K + 1;
    register int Maxn = 0;
    register int i, j;
    for (i = 1; i <= N; ++ i)
        for (j = 1; j <= M; ++ j)
            read (number[i][j]), Maxn = max (Maxn, number[i][j]);
    T = N + M + Max * Max + 1;
    int l = 0, r = Maxn, Mid;
    int Answer;

    for (; l <= r; )
    {
        Mid = l + r >> 1;
        if (Check (Mid))
        {
            r = Mid - 1;
            Answer = Mid;
        }
        else
            l = Mid + 1;
    }

    printf ("%d", Answer);
    return 0;
}
int ZlycerQan = Main ();
int main (int argc, char *argv[]) {;}
时间: 2024-10-10 20:56:26

LibreOJ #2006. 「SCOI2015」小凸玩矩阵的相关文章

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 大的数字的最小值是多少. 输入格式 第一行给出三个整数

LibreOJ #2009. 「SCOI2015」小凸玩密室

二次联通门 : LibreOJ #2009. 「SCOI2015」小凸玩密室 /* LibreOJ #2009. 「SCOI2015」小凸玩密室 树形dp 做到这么正常的题突然感觉好不适应.... 考虑转移 f[x][y] 表示从x点转移到y点的代价 则我们需要处理出以x为根的子树的代价 讨论处理一下即可(有没有左儿子,有没有右儿子,或是都有) 但是这样转移是O(N^2)的 所以我们考虑优化 显然有很多转移是不需要的 比如y在x的子树中时就没必要转移 那么考虑优化 设g[x][i]表示走完x的子

—Libre#2009. 「SCOI2015」小凸玩密室

#2009. 「SCOI2015」小凸玩密室 内存限制:256 MiB时间限制:1000 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: 匿名 提交提交记录统计讨论测试数据 题目描述 小凸和小方相约玩密室逃脱,这个密室是一棵有 n nn 个节点的完全二叉树,每个节点有一个灯泡.点亮所有灯泡即可逃出密室.每个灯泡有个权值 Ai A_iA?i??,每条边也有个权值 bi b_ib?i??. 点亮第 1 11 个灯泡不需要花费,之后每点亮一个新的灯泡 V VV 的花费,等于上一个被点亮的

「SCOI2015」小凸玩密室

题目描述 小凸和小方相约玩密室逃脱,这个密室是一棵有 $n$ 个节点的完全二叉树,每个节点有一个灯泡.点亮所有灯泡即可逃出密室.每个灯泡有个权值 $A_i$,每条边也有个权值 $b_i$. 点亮第 $1$ 个灯泡不需要花费,之后每点亮一个新的灯泡 $V$ 的花费,等于上一个被点亮的灯泡 $U$ 到这个点 $V$ 的距离 $D(u, v)$,乘以这个点的权值 $A_v$. 在点灯的过程中,要保证任意时刻所有被点亮的灯泡必须连通,在点亮一个灯泡后必须先点亮其子树所有灯泡才能点亮其他灯泡.请告诉他们,

[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 #2007. 「SCOI2015」国旗计划

二次联通门 : LibreOJ #2007. 「SCOI2015」国旗计划 --by Claris /* LibreOJ #2007. 「SCOI2015」国旗计划 跪膜Claris... */ #include <cstdio> #include <iostream> #include <algorithm> const int BUF = 12312312; char Buf[BUF], *buf = Buf; inline void read (int &

【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<

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

【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个不