[ SCOI 2015 ] 小凸玩矩阵

题目

Luogu
LOJ
Acwing

思路

1.png

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 610, M = 500010, INF = 2e9;
int n, m, k, S, T, a[310][310];
int h[N], ptr[M], val[M], f[M], idx;
int cur[N], q[N], d[N];
void add(int a, int b, int c) { f[idx] = c, val[idx] = b, ptr[idx] = h[a], h[a] = idx++; }
void add(int a, int b, int c, int d) { add(a, b, c), add(b, a, d); }
bool BFS() {
	int hh = 0, tt = -1;
    memset(d, -1, sizeof d);
    d[S] = 0, q[++tt] = S, cur[S] = h[S];
    for (int t = q[hh]; hh <= tt; hh++, t = q[hh]) 
        for (int i = h[t], v = val[i]; i != -1; i = ptr[i], v = val[i]) {
            if (d[v] != -1 || !f[i]) continue;
            d[v] = d[t] + 1, cur[v] = h[v], q[++tt] = v;
            if (v == T) return true;
        }
    return false;
}
int find(int u, int limit) {
	if (u == T) return limit;
	int flow = 0;
	for (int i = cur[u], v = val[i]; i != -1 && flow < limit; i = ptr[i], v = val[i]) {
		cur[u] = i;
		if (d[v] == d[u] + 1 && f[i]) {
			int t = find(v, min(f[i], limit - flow));
			if (!t) d[v] = -1;
			f[i] -= t, f[i ^ 1] += t, flow += t;
		}
	}
	return flow;
}
int Dinic() {
	int res = 0;
	for (int flow = 0; BFS(); flow = 0)
	    while (flow = find(S, INF)) res += flow;
	return res;
}
bool check(int mid) {
	memset(h, -1, sizeof h), idx = 0;
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= m; j++)
		    // 连边
			if (a[i][j] <= mid)
			    add(i, j + n, 1, 0);
	// 源点汇点连边
	for (int i = 1; i <= n; i++) add(S, i, 1, 0);
	for (int j = 1; j <= m; j++) add(j + n, T, 1, 0);
	int t = Dinic();
	return t >= n + 1 - k;
}
int main() {
	cin >> n >> m >> k;
	S = 0, T = n + m + 1;
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= m; j++)
			cin >> a[i][j];
	int l = 1, r = 1e9;
	while (l < r) {
		int mid = l + r >> 1;
		if (check(mid)) r = mid;
		else l = mid + 1;
	}
	cout << r << endl;
	return 0;
}
posted @ 2021-04-06 13:01  Protein_lzl  阅读(58)  评论(0编辑  收藏  举报