20200923 SCOI模拟T1(网络流/贪心)

T1 P4251 [SCOI2015]小凸玩矩阵

思路:
直接二分答案
考虑要从小于等于二分值的点中选出 n − k + 1 n-k+1 nk+1

考场想法:
脑子抽了,没想出正解……
于是……我贪心过了???
每次找到点数最少的行
在这一行中找到点数最少的列
然后选它们的交点

正解:
对每一行建点,每一列建点
源点连行,列连汇点
行连可选的点连列
流量全为一
跑网络流
判断最大流量

代码:
mine

#include <bits/stdc++.h>
using namespace std;
namespace IO {
char buf_[1 << 21], *p1_ = buf_, *p2_ = buf_;
#define ch()                                                                 \
  (p1_ == p2_ &&                                                             \
           (p2_ = (p1_ = buf_) + fread(buf_, 1, 1 << 21, stdin), p1_ == p2_) \
       ? EOF                                                                 \
       : *p1_++)
inline int in() {
  int s = 0, f = 1;
  char x = ch();
  for (; x < '0' || x > '9'; x = ch())
    if (x == '-') f = -1;
  for (; x >= '0' && x <= '9'; x = ch()) s = (s * 10) + (x & 15);
  return f == 1 ? s : -s;
}
char _buf[1 << 21];
int _pos = -1;
inline void flush() {
  fwrite(_buf, 1, _pos + 1, stdout);
  _pos = -1;
}
inline void pc(char x) {
  if (_pos == (1 << 21) - 1) flush();
  _buf[++_pos] = x;
}
inline void out(int x) {
  char k[30];
  int pos = 0;
  if (!x) return pc('0');
  if (x < 0) pc('-'), x = -x;
  while (x) k[++pos] = (x % 10) | 48, x /= 10;
  for (int i = pos; i; i--) pc(k[i]);
}
}  // namespace IO
using namespace IO;

const int A = 300;
const int INF = 1e9 + 5;
int n, m, K;
int p[A][A];
int nh[A], nl[A];

inline int check(int x) {
  for (int i = 1; i <= m; i++) nh[i] = nl[i] = 0;
  for (int i = 1; i <= n; i++)
    for (int j = 1; j <= m; j++)
      if (p[i][j] <= x) nh[i]++, nl[j]++;
  nh[0] = nl[0] = INF;
  int pos = 0;
  for (int tm = 1; tm <= n - K + 1; tm++) {
    int h = 0;
    for (int i = 1; i <= n; i++)
      if (nh[i] && nh[i] < nh[h]) h = i;
    if (!h) {
      pos = 1;
      break;
    }
    int l = 0;
    for (int i = 1; i <= m; i++)
      if (p[h][i] <= x && nl[i] && nl[i] < nl[l]) l = i;
    nh[h] = 0, nl[l] = 0;
    for (int i = 1; i <= n; i++)
      if (nh[i] && p[i][l] <= x) nh[i]--;
  }
  if (pos) return 0;
  return 1;
}

signed main() {
  n = in(), m = in(), K = in();
  for (int i = 1; i <= n; i++)
    for (int j = 1; j <= m; j++) p[i][j] = in();
  int L = 1, R = 1e9, ans = 0;
  while (L <= R) {
    int mid = (L + R) >> 1;
    if (check(mid))
      R = mid - 1, ans = mid;
    else
      L = mid + 1;
  }
  out(ans), pc('\n');
  flush();
  return 0;
}

std

#include <bits/stdc++.h>
using namespace std;
namespace IO {
char buf_[1 << 21], *p1_ = buf_, *p2_ = buf_;
#define ch()                                                                 \
  (p1_ == p2_ &&                                                             \
           (p2_ = (p1_ = buf_) + fread(buf_, 1, 1 << 21, stdin), p1_ == p2_) \
       ? EOF                                                                 \
       : *p1_++)
inline int in() {
  int s = 0, f = 1;
  char x = ch();
  for (; x < '0' || x > '9'; x = ch())
    if (x == '-') f = -1;
  for (; x >= '0' && x <= '9'; x = ch()) s = (s * 10) + (x & 15);
  return f == 1 ? s : -s;
}
char _buf[1 << 21];
int _pos = -1;
inline void flush() {
  fwrite(_buf, 1, _pos + 1, stdout);
  _pos = -1;
}
inline void pc(char x) {
  if (_pos == (1 << 21) - 1) flush();
  _buf[++_pos] = x;
}
inline void out(int x) {
  char k[30];
  int pos = 0;
  if (!x) return pc('0');
  if (x < 0) pc('-'), x = -x;
  while (x) k[++pos] = (x % 10) | 48, x /= 10;
  for (int i = pos; i; i--) pc(k[i]);
}
}  // namespace IO
using namespace IO;

const int A = 300;
const int N = 1e6 + 5;
const int INF = 1e9 + 5;
int n, m, K;
int p[A][A];
int head[N], tot_road = 1;
struct Road {
  int nex, to, w;
} road[2 * N];
inline void edge(int x, int y, int w) {
  road[++tot_road] = {head[x], y, w}, head[x] = tot_road;
  road[++tot_road] = {head[y], x, 0}, head[y] = tot_road;
}
inline int d(int x, int y) { return x * (m + 1) + y; }

#define S 0
#define T (n + 1) * (m + 1) + 1

int maxflow;
int dep[N], sum[N];

inline void BFS() {
  for (int i = S; i <= T; i++) dep[i] = -1, sum[i] = 0;
  queue<int> q;
  dep[T] = 0, sum[dep[T]]++;
  q.push(T);
  while (!q.empty()) {
    int x = q.front();
    q.pop();
    for (int y = head[x]; y; y = road[y].nex) {
      int z = road[y].to;
      if (dep[z] != -1) continue;
      dep[z] = dep[x] + 1, sum[dep[z]]++;
      q.push(z);
    }
  }
  return;
}

inline int DFS(int x, int flow) {
  if (x == T) {
    maxflow += flow;
    return flow;
  }
  int used = 0;
  for (int y = head[x]; y; y = road[y].nex) {
    int z = road[y].to, w = road[y].w;
    if (dep[z] + 1 == dep[x] && w) {
      int after = DFS(z, min(flow - used, w));
      if (after) {
        road[y].w -= after;
        road[y ^ 1].w += after;
        used += after;
      }
    }
    if (used == flow) return used;
  }
  if (!--sum[dep[x]]) dep[T] = T + 1;
  sum[++dep[x]]++;
  return used;
}

inline void ISAP() {
  maxflow = 0;
  BFS();
  while (dep[T] <= T) DFS(S, INF);
  return;
}

inline int check(int x) {
  tot_road = 1;
  for (int i = S; i <= T; i++) head[i] = 0;
  for (int i = 1; i <= n; i++) edge(S, d(i, 0), 1);
  for (int i = 1; i <= m; i++) edge(d(0, i), T, 1);
  for (int i = 1; i <= n; i++)
    for (int j = 1; j <= m; j++)
      if (p[i][j] <= x)
        edge(d(i, 0), d(i, j), INF), edge(d(i, j), d(0, j), INF);
  ISAP();
  return maxflow >= n - K + 1;
}

signed main() {
  n = in(), m = in(), K = in();
  for (int i = 1; i <= n; i++)
    for (int j = 1; j <= m; j++) p[i][j] = in();
  int L = 1, R = 1e9, ans = 0;
  while (L <= R) {
    int mid = (L + R) >> 1;
    if (check(mid))
      R = mid - 1, ans = mid;
    else
      L = mid + 1;
  }
  out(ans), pc('\n');
  flush();
  return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值