题意
给你一个 n ∗ n n*n n∗n大小的网格,每一行最大值 b i b_i bi,每一列最大值 c i c_i ci,你需要对一些点赋值,使得总的赋值和最小。
分析
将每个数值对应的行,以及每个数值对应的列分别进行存储。枚举每一个数值,范围 [ 1 ∼ k ] [1\sim k] [1∼k]。
枚举当前数值所对应的行和列,如果当前行列可以填数,则将行和列建边,求出行和列的最大匹配数。
当前数值的贡献为:(当前值对应的行数+当前值对应列数-最大匹配数)*当前值。
使用
v
e
c
t
o
r
vector
vector进行存储,所对应的值就是
[
v
1
[
n
o
w
]
.
s
i
z
e
(
)
+
v
2
[
n
o
w
]
.
s
i
z
e
(
)
−
m
a
x
p
i
p
e
i
]
∗
n
o
w
[v_1[now].size()+v_2[now].size()-max_{pipei}]*now
[v1[now].size()+v2[now].size()−maxpipei]∗now,(
n
o
w
now
now为当前值)
此处的最大匹配值可以理解为当前行和列的最大值均已经满足,可以填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;
}