loj2006「SCOI2015」小凸玩矩陣

題目說使第k大最小,很容易想到二分。
二分以後,我們就要判斷是否能夠選出n-k+1個<=mid的數。
又因爲每行每列都只能選一個數,我記得這種問題以前學匈牙利算法的時候做過,所以當存在ai,j<=mida_{i,j}<=mid的時候,我們從i向j連邊,然後跑一次匈牙利算法,看看最大匹配是否>=n-k+1即可
參考代碼

#include <cstring>
#include <iostream>
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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章