题意

给你一个大小的网格,每一行最大值,每一列最大值,你需要对一些点赋值,使得总的赋值和最小。

分析

将每个数值对应的行,以及每个数值对应的列分别进行存储。枚举每一个数值,范围

枚举当前数值所对应的行和列,如果当前行列可以填数,则将行和列建边,求出行和列的最大匹配数。

当前数值的贡献为:(当前值对应的行数+当前值对应列数-最大匹配数)*当前值。
使用进行存储,所对应的值就是,(为当前值)

此处的最大匹配值可以理解为当前行和列的最大值均已经满足,可以填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;
}