题意
给你一个大小的网格,每一行最大值
,每一列最大值
,你需要对一些点赋值,使得总的赋值和最小。
分析
将每个数值对应的行,以及每个数值对应的列分别进行存储。枚举每一个数值,范围。
枚举当前数值所对应的行和列,如果当前行列可以填数,则将行和列建边,求出行和列的最大匹配数。
当前数值的贡献为:(当前值对应的行数+当前值对应列数-最大匹配数)*当前值。
使用进行存储,所对应的值就是
,(
为当前值)
此处的最大匹配值可以理解为当前行和列的最大值均已经满足,可以填0的最大数量。
代码
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N = 1e4+10, M = 1e6 + 10, inf = 1e8; int n, m, k, x; int mp[N][N]; vector<int> G1[M], G2[M]; vector<int> G[N]; int st[N], match[N]; bool dfs(int u){ for(auto j : G[u]){ if(st[j]) continue; st[j] = 1; if(match[j] == -1 || dfs(match[j])){ match[j] = u; return 1; } } return 0; } int cal(){ memset(match, -1, sizeof(match)); int res = 0; for(int i = 1; i <= n + n; i++){ memset(st, 0, sizeof(st)); if(dfs(i)) res++; } return res; } int main(){ ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); cin>>n>>m>>k; for(int i = 1; i <= n; i++) cin>>x, G1[x].push_back(i); for(int i = 1; i <= n; i++) cin>>x, G2[x].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 now = k; now >= 1; now--){ if(G1[now].size() == 0 && G2[now].size() == 0) continue; for(int i = 1; i <= n + n; i++) G[i].clear(); for(auto i : G1[now]) for(auto j : G2[now]) if(mp[i][j-n]) G[i].push_back(j), G[j].push_back(i); // 建图 ll maxpipei = cal()/2; ll maxm = G1[now].size() + G2[now].size() - maxpipei; ans = ans + maxm * now; } cout<<ans<<endl; return 0; }