Educational Codeforces Round 135 (Rated for Div. 2) F. Fishermen 二分图最小带权匹配|匈牙利
不用真的建图,真的建图两人之间的代价不好算。
等价转化为对给定的ai找出bi,使得bi=k*a[i],且互不相同
k的上界为n,简易证明:
[
若a[i]互不相等,全部选a[i]*n会比a[i]*(n+1)更好;
若存在一对a[i]相等,可以使其中一个数取n-1
若再存在一对,取n-1..
必能在n步内对所有的a[i]赋值完。
]
点和边都是n²级别,对每个i,向a[i]*k连边,跑最大匹配就可以满足互不相同(匹配的定义)
那b要尽可能小怎么保证?以及sigma(bi)要尽可能小怎么保证?
对所有的a[i]*k从小到大排序,逐个尝试是否能匹配,可以的话把a[i]*k加入答案
这样贪心地保证了sigma(bi)尽可能小,且b一定尽可能地小(否则会先被匹配到)
最后一个问题,匈牙利算法是点数*边数,在这题是n4方级别,优化:
如果上一次没匹配成功,可以不用清空vis数组(理解:如果没有匹配成功,再换个点效果也一样,只有匹配成功了才是一个新图)
嗯加了这个玄学的优化可以变成n3。
细节:
直接用a[i]*k做一个点的话会爆int数组,要开map
#include<bits/stdc++.h> using namespace std; const int maxn=1000*1000+5 ; int d,match[maxn],vis[maxn],l[maxn],n,m; struct lys{ int from,to,nex; }e[maxn<<1]; int cnt=0; map<int,int>head; // head 和 e是同级的 void add(int from,int to){ cnt++;e[cnt].from=from;e[cnt].to=to;e[cnt].nex=head[from];head[from]=cnt; } int dfs(int x) { for(int i=head[x];i;i=e[i].nex) { int to=e[i].to; if(vis[to]) continue; vis[to]=1; if(!match[to]||dfs(match[to])) { match[to]=x; return 1; } } return 0; } int main() { //freopen("lys.in","r",stdin); int tot=0; cin>>n; for(int i=1;i<=n;i++){ int w;cin>>w; for(int j=1;j<=n;j++){ int p=w*j; tot++; l[tot]=p; add(p,i);// build directed edge } } sort(l+1,l+tot+1); int len=unique(l+1,l+tot+1)-(l+1); long long ans=0; bool find=0; for(int i=1;i<=len;i++) { // cout<<i<<" "<<l[i]<<endl; if(find) memset(vis,0,sizeof(vis)); find=dfs(l[i]); if(find) ans+=(long long)(l[i]); } cout<<ans; }
分类:
图论
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)