Minimum grid
题意:
一个n * n的矩阵,有m个位置需要填数,填的数的范围是0<=k<=1e6,需要满足第i行的最大值是b,第j列的最大值是ci,求一个满足条件的最小代价
n<=2e3,m<=8e5,k<=1e6
题解:
如果直接填,我们需要满足每行每列的最大值,第i行最大值是a,第j行最大值是b,我们需要第i行单独有一个格子权值是a,第j行单独有一个格子的权值是b,这样代价是a+b,但是如果第i行和第j行的最大值都是a,我们可以直接在(i,j)这个格子上放a,这样即满足条件且代价降低(用一个a干了两个a的事)
如果现在第1行,第2行,第3行,第3列,第4列的最大值都是a,那么才怎么分配呢?我们把行放一侧,列放一侧,这不就是二分图吗,跑最大匹配即可,最大匹配就省下的a的数量。也就是(当前值对应的行数+当前值对应的列数-最大匹配值) * 当前值
当然前提是这几个位置都允许填
我们可以直接枚举最大值K,跑多次二分图,然后计算每次贡献得到答案
不过,每种权值互相不影响,可以建立多个二分图一次跑完
代码:
#include<bits/stdc++.h>
#define debug(a,b) printf("%s = %d\n",a,b);
typedef long long ll;
using namespace std;
//Fe~Jozky
const ll INF_ll=1e18;
const int INF_int=0x3f3f3f3f;
inline ll read(){ll s=0,w=1ll;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')w=-1ll;ch=getchar();}while(ch>='0'&&ch<='9') s=s*10ll+((ch-'0')*1ll),ch=getchar();//s=(s<<3)+(s<<1)+(ch^48);return s*w;
}
const int maxn=3e3+9;
int a[maxn],b[maxn];
vector<int>g[maxn];
int match[maxn];
bool vis[maxn];
ll ans;
int n,m,k;
bool dfs(int x){for(int v:g[x]){if(vis[v])continue;vis[v]=1;if(!match[v]||dfs(match[v])){match[v]=x;return 1;}}return 0;
}
int main()
{cin>>n>>m>>k;for(int i=1;i<=n;i++)cin>>a[i];for(int j=1;j<=n;j++)cin>>b[j];while(m--){int x,y;cin>>x>>y;if(a[x]==b[y])//如果该行最大值等于列最大值 g[x].push_back(y);}for(int i=1;i<=n;i++){memset(vis,0,sizeof(vis));dfs(i);}for(int i=1;i<=n;i++)//没有优化的结果 ans+=a[i]+b[i];for(int i=1;i<=n;i++)if(match[i])ans-=b[i];//可以省掉b[i] cout<<ans;
}