2021牛客暑期多校训练营3 C.Minimum grid(二分图匹配)
Posted issue是fw
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2021牛客暑期多校训练营3 C.Minimum grid(二分图匹配)相关的知识,希望对你有一定的参考价值。
最差情况下答案是 ∑ i = 1 n a i + ∑ i = 1 n b i \\sum\\limits_{i=1}^n a_i+\\sum\\limits_{i=1}^nb_i i=1∑nai+i=1∑nbi
考虑减小答案的唯一方式是在格子 ( i , j ) (i,j) (i,j)放下数字且 a i a_i ai,且此时 a i = = b j a_i==b_j ai==bj就同时满足一行一列
这样就省去了一个 a i a_i ai的代价
于是考虑单独提出权值为 w w w的行和列,问题转化为一个匹配问题
若格子 ( i , j ) (i,j) (i,j)存在可以由 i i i行向 j j j列连边,在这个位置填充数字 w w w可以省掉 w w w的费用
求一个最大匹配即可
对于每种权值都这样做一遍,由于保证没有一种权值出现次数多于 500 500 500,这保证了二分图的边不会很多
所以复杂度是对的
#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e3+10;
int n,m,k,girl[2009],used[2002];
bool vis[maxn][maxn];
vector<int>vec[maxn],row[maxn],col[maxn];
bool find(int u)
{
for(auto v:vec[u] )
{
if( used[v] ) continue;
used[v] = 1;
if( girl[v]==0 || find( girl[v] ) )
{
girl[v] = u;
return true;
}
}
return false;
}
int main()
{
cin >> n >> m >> k;
for(int i=1;i<=n;i++)
{
int x; scanf("%d",&x );
row[x].push_back( i );
}
for(int i=1;i<=n;i++)
{
int x; scanf("%d",&x );
col[x].push_back( i );
}
for(int i=1;i<=m;i++)
{
int l,r; scanf("%d%d",&l,&r );
vis[l][r] = 1;
}
long long ans = 0;
for(int w=k;w>=1;w--)//枚举每一种权值,那么对应的行和列
{
if( row[w].size()==0 && col[w].size()==0 ) continue;
for(auto u:row[w] )
for(auto v:col[w] )
{
if( vis[u][v] )
vec[u].push_back( v );//u->v
}
int mat = 0;
for(auto u:row[w] )
{
for(auto v:col[w] ) used[v] = 0;
if( find(u) ) mat++;
}
for(auto v:col[w] ) girl[v] = 0;
ans += 1ll*( row[w].size()+col[w].size()-mat )*w;
for(auto u:row[w] ) vec[u].clear();
}
cout << ans;
}
以上是关于2021牛客暑期多校训练营3 C.Minimum grid(二分图匹配)的主要内容,如果未能解决你的问题,请参考以下文章
2021牛客暑期多校训练营1 - F - Find 3-friendly Integers - 题解