2021牛客暑期多校训练营3 C.Minimum grid 二分图最大匹配
Posted kaka0010
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2021牛客暑期多校训练营3 C.Minimum grid 二分图最大匹配相关的知识,希望对你有一定的参考价值。
原题链接:https://ac.nowcoder.com/acm/contest/11254/C
题意
有一个n*n的矩阵,要求在m个位置填上个数,每个数的大小是[0,k],给定每行每列的最大值,问填数总和的最小值。
分析
如果直接填数,我们发现最多只需要填2*n个数,即将所有的最大值都填上去。但我们发现,如果第i行的最大值和第j列的最大值相等,那么将aij填上数,可以少填一个数。因此我们推广一下,如果有n行和m列最大值相等,那么我们进行一次最大匹配,得到的匹配数就是减少填的数字。那么我们可以枚举最大值,然后不断进行二分图最大匹配,每个数值i的贡献也就是 ( n + m − m a t c h ) ∗ i (n+m-match)*i (n+m−match)∗i。
这题特地说明了最大值个数不会超过500,因此直接用匈牙利去跑都是足够的。
Code
#include <bits/stdc++.h>
#define lowbit(i) i & -i
#define Debug(x) cout << x << endl
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const ll INF = 1e18;
const double eps = 1e-3;
const int N = 1e6 + 10;
const int M = 1e6 + 10;
const int MOD = 998244353;
int n, m, k, vis[2005], match[2005];
vector<int> g[N], ve[N];
int mp[2005][2005];
bool dfs(int x) {
for (auto v : g[x]) {
if (!vis[v]) {
vis[v] = 1;
if (!match[v] || dfs(match[v])) {
match[v] = x;
return true;
}
}
}
return false;
}
int work(vector<int> r, vector<int> c) {
if (r.empty() || c.empty()) return 0;
memset(vis, 0, sizeof vis);
memset(match, 0, sizeof match);
for (int i = 1; i <= n; i++) g[i].clear();
for (int i = 0; i < r.size(); i++) {
for (int j = 0; j < c.size(); j++) {
int u = r[i], v = c[j];
if (mp[u][v]) g[u].push_back(v);
}
}
int ans = 0;
for (int i = 1; i <= n; i++) {
if (g[i].empty()) continue;
memset(vis, 0, sizeof vis);
if (dfs(i)) ans++;
}
return ans;
}
void solve() {
cin >> n >> m >> k;
for (int i = 1; i <= n; i++) {
int b; cin >> b;
ve[b].push_back(i);
}
for (int i = 1; i <= n; i++) {
int c; cin >> c;
ve[c].push_back(i+n);
}
for (int i = 1; i <= m; i++) {
int x, y; cin >> x >> y;
mp[x][y] = 1;
}
ll ans = 0;
for (int i = k; ~i; i--) {
if (ve[i].empty()) continue;
vector<int> c, r;
for (auto it : ve[i]) {
//cout << i << " " << it << endl;
if (it <= n) r.push_back(it);
else c.push_back(it-n);
}
ans += 1ll*(r.size() + c.size() - work(r, c)) * i;
}
cout << ans << endl;
}
signed main() {
ios_base::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
#ifdef ACM_LOCAL
freopen("input", "r", stdin);
freopen("output", "w", stdout);
signed test_index_for_debug = 1;
char acm_local_for_debug = 0;
do {
if (acm_local_for_debug == '$') exit(0);
if (test_index_for_debug > 20)
throw runtime_error("Check the stdin!!!");
auto start_clock_for_debug = clock();
solve();
auto end_clock_for_debug = clock();
cout << "Test " << test_index_for_debug << " successful" << endl;
cerr << "Test " << test_index_for_debug++ << " Run Time: "
<< double(end_clock_for_debug - start_clock_for_debug) / CLOCKS_PER_SEC << "s" << endl;
cout << "--------------------------------------------------" << endl;
} while (cin >> acm_local_for_debug && cin.putback(acm_local_for_debug));
#else
solve();
#endif
return 0;
}
以上是关于2021牛客暑期多校训练营3 C.Minimum grid 二分图最大匹配的主要内容,如果未能解决你的问题,请参考以下文章
2021牛客暑期多校训练营1 - F - Find 3-friendly Integers - 题解