题意
给定一个(n imes n)的方阵,有(m)个位置需要填数,且每一行的数的最大值为(b_i),每一列数的最大值为(c_i),求方阵中所有数和的最小值。
(1le nle 2 imes 10^3,1le mle 8 imes 10^5,1le b_i,c_ile k,1le kle 10^6),且所有(b_i,c_i)中相同的值最多出现(500)次。
题解
填入的数只需要是(b_i,c_i)或(0)。从大到小一次考虑每一种权值(v),将(b_i=v)的行和(c_i=v)得列提出来构成一个子阵,对行和列建点,对可以填数的位置的行列之间连边,则这种权值对答案的贡献为(最小边覆盖*权值=(行数+列数-最大匹配)*权值)。由于各个权值之间互不干扰,故不需要对每个权值分别建图,直接建一个图后跑二分图匹配即可。
#include <bits/stdc++.h>
#define pb(x) emplace_back(x)
using namespace std;
using ll=long long ;
const int N=2005;
int match[N],vis[N];
vector<int> g[N];
int n,m,k,a[N],b[N];
ll ans=0;
int dfs(int u){
for(auto v:g[u])if(!vis[v]){
vis[v]=1;
if(!match[v]||dfs(match[v])){
match[v]=u;return 1;
}
}
return 0;
}
void f1(){
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=n;i++){
cin>>a[i];ans+=a[i];
}
for(int i=1;i<=n;i++){
cin>>b[i];ans+=b[i];
}
while(m--){
int x,y;cin>>x>>y;
if(a[x]==b[y]){g[x].pb(y);}
}
for(int i=1;i<=n;i++){
memset(vis,0,sizeof(vis));
dfs(i);
}
for(int i=1;i<=n;i++){
if(match[i])ans-=b[i];
}
cout<<ans;
}
int main(){
f1();
return 0;
}