• 2021牛客暑期多校训练营3  C.Minimum grid  (思维,二分图最大匹配)_二分图

  • 题意:有一个\(n\)x\(n\)的矩阵,有\(m\)个单位有权值,其他单位均为空,给你两个数组\(a\)\(b\)\(a[i]\)表示第\(i\)行的最大元素,\(b[i]\)表示第\(i\)列的最大元素,你需要在这\(m\)个单位中填值,在满足\(a\)\(b\)数组的条件下求矩阵最小\(sum\).

  • 题解:将最大值为\(k\)\(a[i]\)\(b[i]\)拿出来单独看,很明显,如果行和列相交,那么将这个点填\(k\)可以同时满足一行和一列,所以我们要尽可能的填这些相交的点.那么经典套路,将行和列抽象成点,\(m\)个单位有权值,也就是\(m\)条边,然后去枚举\(k\),权值为\(k\)的行和列可以形成一张二分图,行在左边,列在右边,求行和列的最多相交点,就是求二分图的最大匹配.因为题目说了\(a\)\(b\)的权值数最大\(500\)个,\(4000\)个点,用匈牙利算法是妥妥的能跑过去的.

  • 代码

    #include <bits/stdc++.h>
    #define ll long long
    #define fi first
    #define se second
    #define pb push_back
    #define me memset
    #define rep(a,b,c) for(int a=b;a<=c;++a)
    #define per(a,b,c) for(int a=b;a>=c;--a)
    const int N = 1e6 + 10;
    const int mod = 1e9 + 7;
    const int INF = 0x3f3f3f3f;
    using namespace std;
    typedef pair<int,int> PII;
    typedef pair<ll,ll> PLL;
    ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
    ll lcm(ll a,ll b) {return a/gcd(a,b)*b;}
    
    int n,m,k;
    int a[N],b[N];
    vector<int> row[N],col[N];
    int vis[4000][4000];
    vector<int> edge[N];
    bool st[4000];
    int match[N];
    
    bool find(int u){
        for(auto w:edge[u]){
            if(!st[w]){
                st[w]=true;
                if(match[w]==0 || find(match[w])){
                    match[w]=u;
                    return true;
                }
            }
        }
        return false;
    }
    
    int main() {
        ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
        cin>>n>>m>>k;
        rep(i,1,n){
            cin>>a[i];
            row[a[i]].pb(i);
        }
        rep(i,1,n){
            cin>>b[i];
            col[b[i]].pb(i+n);
        }
        rep(i,1,m){
            int u,v;
            cin>>u>>v;
            vis[u][v]=true;
        }
        ll ans=0;
        rep(i,1,k){  
            if((int)row[i].size()==0 && (int)col[i].size()==0) continue; 
            rep(j,1,2*n) edge[j].clear();
            for(auto w:row[i]){
                for(auto ww:col[i]){
                    if(vis[w][ww-n]){
                        edge[w].pb(ww);
                        edge[ww].pb(w);
                    }
                }
            }
            ll res=0;
            me(match,0,sizeof(match));
            rep(j,1,2*n){
                me(st,false,sizeof(st));
                if(find(j)) res++;
            }
            ans+=1ll*((int)row[i].size()+(int)col[i].size()-res/2)*i;
        }
        cout<<ans<<'\n';
    
    
        return 0;
    }
    
    
???????????????????????????????????????????? ???????????????????????????????? ???????????? ???????????????? ???????????????? ???????????????????????????????? ???????? ????????????????