2021牛客暑期多校训练营3 C Minimum grid 思维+二分图匹配

题意

给你一个 n ∗ n n*n nn大小的网格,每一行最大值 b i b_i bi,每一列最大值 c i c_i ci,你需要对一些点赋值,使得总的赋值和最小。

分析

将每个数值对应的行,以及每个数值对应的列分别进行存储。枚举每一个数值,范围 [ 1 ∼ k ] [1\sim k] [1k]

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

当前数值的贡献为:(当前值对应的行数+当前值对应列数-最大匹配数)*当前值。
使用 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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值