2025洛谷省选模拟赛D2T2“flower” 题解
2025洛谷省选模拟赛D2T2“flower” 题解
这就是一个二分图最大权完美匹配,用费用流可以解决,期望
因为费用流的复杂度为
,可以考虑减少图的边数以减小复杂度。
一个函数有多种表示形式,我们应尽量选择与算法相匹配的。
因为
-
。 -
。 -
。 -
相当于是找这四项的最大值,这与我们”最大费用最大流“的算法刚好相符,并且这样贡献独立。
具体可以新建
网络流可行数据范围往
估
可以得
可以得
下文中把代表每个花朵的左部点称作
发现这样建图有一个特点那就是
模拟费用流要对于一次增广考虑其性质。
-
发现原最大流量为
但每次增广的流量恰好为 。所以其本质是找了 次最长路。 -
那么每次增广的路径一定经过
。如果我们能不考虑 直接在 之间转移,那么点数会减少很多。
所以我们考虑
-
:即 经过左部点到 ,这是简单的,根据增广的过程,一定会选择一个没有被选择的左部点 进行增广,我们直接在 中维护这些 。 -
:即 经过右部点到 ,同理也一定会选择一个没有没选择过的右部点 ,在 中维护这些 。 -
即 经过右部点到 ,这是一个退流操作:其本质就是将 变为了 所以转移边权应该是 。 -
即 经过左部点 到达 ,这也是一个推流操作,本质是将 变为了 ,所以转移边权应该是 。
下面是第三,第四种转移的图示。
那么对于一次最长路,我们只需要
在选出一次后,我们应该对于最长路径上的所有
对于一条更新的连边
对于一条更新的连边
由于一次最多添加
最后复杂度(大致估计常数)
代码:
#include<bits/stdc++.h>
#define int long long
using namespace std;
typedef pair<int,int> pa;
const int NN=4e5+5,INF=0x3f3f3f3f3f3f3f3f;
int n;
int d[10][10],id[10][10];
priority_queue<pa> q[10][10];//第1维是边权,第2维是转移过程点
int match[NN],s=5,t=6,a[NN][10],ans;
bool rit[NN];//标记为右侧的点
int dis[10],pre[10];
bool vst[NN];
int SPFA(){
memset(dis,0xcf,sizeof dis);//找最长路
queue<int> Q;
Q.push(s);dis[s]=0;vst[s]=1;
while(!Q.empty()){
int x=Q.front();Q.pop();
vst[x]=0;
for(int y=1;y<=6;y++){
if(dis[y]>=dis[x]+d[x][y])continue;
dis[y]=dis[x]+d[x][y];
pre[y]=x;
if(!vst[y]){
Q.push(y);
vst[y]=1;
}
}
}
return dis[t];
}
signed main(){
cin>>n;
for(int i=1;i<=n<<1;i++){
int c,l,w;cin>>c>>l>>w;
if(!c){
a[i][1]=l+w,a[i][2]=w-l,a[i][3]=l-w,a[i][4]=-l-w;
for(int j=1;j<=4;j++)q[s][j].push({a[i][j],i});
}else{
rit[i]=1;
a[i][1]=-l-w,a[i][2]=l-w,a[i][3]=w-l,a[i][4]=l+w;
for(int j=1;j<=4;j++)q[j][t].push({a[i][j],i});
}
}
for(int cs=1;cs<=n;cs++){//每次网络流都增加1的流量,那么总共恰好时找n次最长路
//更新一下边权
for(int i=1;i<=6;i++){
for(int j=1;j<=6;j++){
d[i][j]=-INF;
while(!q[i][j].empty()){
int u=q[i][j].top().second;//注意这里不能pop因为若本次没有使用这条边,其还是要保留的
bool flag=0;//检验这条边是否被删除,相当于一个懒惰删除
if(!rit[u]){//这是一个左部点
if(i==s)flag|=!match[u];//相当于新开一条流
else flag|=match[u]==i;//相当于,对于一个V,要求其真的指向自己
}else{//这是一个右部点
if(j==t)flag|=!match[u];
else flag|=match[u]==j;
}
if(!flag)q[i][j].pop();
else{
id[i][j]=u;
d[i][j]=q[i][j].top().first;
break;
}
}
}
}
ans+=SPFA();//跑最长路
//更新边权
for(int i=t;i!=s;i=pre[i]){//遍历路径
int u=id[pre[i]][i];
if(!rit[u])match[u]=i;
else match[u]=pre[i];
for(int j=1;j<=4;j++){
if(!rit[u])q[match[u]][j].push({a[u][j]-a[u][match[u]],u});
else q[j][match[u]].push({a[u][j]-a[u][match[u]],u});
}
}
}
cout<<ans;
return 0;
}
作者:lupengheyyds
出处:https://www.cnblogs.com/lupengheyyds/p/18742117
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】