題目說使第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;
}