题目说使第k大最小,很容易想到二分。
二分以后,我们就要判断是否能够选出n-k+1个<=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;
}