题意
给你一个大小的网格,每一行最大值
,每一列最大值
,你需要对一些点赋值,使得总的赋值和最小。
分析
将每个数值对应的行,以及每个数值对应的列分别进行存储。枚举每一个数值,范围。
枚举当前数值所对应的行和列,如果当前行列可以填数,则将行和列建边,求出行和列的最大匹配数。
当前数值的贡献为:(当前值对应的行数+当前值对应列数-最大匹配数)*当前值。
使用进行存储,所对应的值就是
,(
为当前值)
此处的最大匹配值可以理解为当前行和列的最大值均已经满足,可以填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;
} 


京公网安备 11010502036488号