loj2006「SCOI2015」小凸玩矩阵

题目说使第k大最小,很容易想到二分。
二分以后,我们就要判断是否能够选出n-k+1个<=mid的数。
又因为每行每列都只能选一个数,我记得这种问题以前学匈牙利算法的时候做过,所以当存在 a i , j < = m i d a_{i,j}<=mid ai,j<=mid的时候,我们从i向j连边,然后跑一次匈牙利算法,看看最大匹配是否>=n-k+1即可
参考代码

#include 
#include 
using namespace std;
const int N = 1e3 + 6;
int n, m, k, a[256][256];
int tot, Head[N], ver[N * N], Next[N * N];
void add(int u, int v) {
	tot++; 
	ver[tot] = v;
	Next[tot] = Head[u];
	Head[u] = tot;
}

bool vis[N]; int match[N];
bool dfs(int u) {
	for (int i = Head[u]; i; i = Next[i]) {
		int v = ver[i];
		if (!vis[v]) {
			vis[v] = 1;
			if (!match[v] || dfs(match[v])) {
				match[v] = u;
				return 1;
			}
		}
	}
	return 0;
}

bool check(int x) {
	tot = 0; memset(Head, 0, sizeof(Head));
	memset(match, 0, sizeof(match));
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= m; j++)
			if (a[i][j] <= x) add(i, j);
	int sum = 0;
	for (int i = 1; i <= n; i++) {
		memset(vis, 0, sizeof(vis));
		sum += dfs(i);
	}
	return sum >= n - k + 1;
}

void solve() {
	int l = -1e9, r = 1e9, mid, ans;
	while (l <= r) {
		mid = (l + r)>>1;
		if (check(mid)) r = mid - 1, ans = mid;
		else l = mid + 1;
	}
	cout << ans << endl;
}

int main() {
	cin >> n >> m >> k;
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= m; j++)
			cin >> a[i][j];
	solve(); return 0;
}

你可能感兴趣的:(loj,各省省选)