Loading

2025洛谷省选模拟赛D2T2“flower” 题解

2025洛谷省选模拟赛D2T2“flower” 题解

这就是一个二分图最大权完美匹配,用费用流可以解决,期望 \(35\) 分。建了 \(\mathcal O(n^2)\) 条边。

因为费用流的复杂度为 \(\mathcal O(n\times m\times maxflow)\),可以考虑减少图的边数以减小复杂度。

一个函数有多种表示形式,我们应尽量选择与算法相匹配的。

因为 \(|a-b|=\max(a-b,b-a)\)。我们将权值拆为四种形式:

  • \((l_i+w_i)-(l_j+w_j)\)

  • \((w_i-l_i)+(l_j-w_j)\)

  • \((l_i-w_i)+(w_j-l_j)\)

  • \(-(l_i+w_i)+(l_j+w_j)\)

相当于是找这四项的最大值,这与我们”最大费用最大流“的算法刚好相符,并且这样贡献独立。

具体可以新建 \(4\) 个点 \(V_1,V_2.V_3.V_4\),对于每个蓝/红花按顺序向其连边,边数变为了 \(\mathcal O(n)\) 由于 \(maxflow=n\),复杂度 \(\mathcal O(n^3)\)。由于:

网络流可行数据范围往 \(10^9\)

可以得 \(55\) 分。

\(0\le l,w\le 2\),总共只有 \(3\times 3\times 2=18\) 中不同的点,直接计数+改容量可以通过。

可以得 \(70\) 分。

下文中把代表每个花朵的左部点称作 \(x\),右部点称作 \(y\),源点称作 \(S\),汇点称作 \(T\),中间的新增点称作 \(V\)。左部点向 \(V\) 的连边的的边权记作 \(E(x,V)\),右部点的记作 \(E(V,y)\)

发现这样建图有一个特点那就是 \(V\) 很少只有四个,且 \(x,y\) 很多,但 \(V\) 是每次增广的必经点于是考虑模拟费用流。

模拟费用流要对于一次增广考虑其性质。

  • 发现原最大流量为 \(n\) 但每次增广的流量恰好为 \(1\)。所以其本质是找了 \(n\) 次最长路。

  • 那么每次增广的路径一定经过 \(S\to V\to\cdots \to V\to T\)。如果我们能不考虑 \(x,y\) 直接在 \(S,V,T\) 之间转移,那么点数会减少很多。

所以我们考虑 \(S,V,T\) 之间的转移,设 \(q[A][B]\) 表示 \(A\to B\) 的转移,将这些转移分为四类:

  • \(S\xrightarrow{x} V\):即 \(S\) 经过左部点到 \(V\),这是简单的,根据增广的过程,一定会选择一个没有被选择的左部点 \(x\) 进行增广,我们直接在 \(q[S][V]\) 中维护这些 \(E(x,V)\)

  • \(V\xrightarrow{y}T\):即 \(V\) 经过右部点到 \(T\),同理也一定会选择一个没有没选择过的右部点 \(y\),在 \(q[V][T]\)中维护这些 \(E(V,y)\)

  • \(V_1\xrightarrow{y}V_2\)\(V_1\) 经过右部点到 \(V_2\),这是一个退流操作:其本质就是将 \(V_2\to y\) 变为了 \(V_1\to y\) 所以转移边权应该是 \(E(V_1,y)-E(V_2,y)\)

  • \(V_1\xrightarrow{x}V_2\)\(V_1\) 经过左部点 \(x\) 到达 \(x\),这也是一个推流操作,本质是将 \(x\to V_1\) 变为了 \(x\to V_2\),所以转移边权应该是 \(E(x,V_2)-E(x,V_1)\)

下面是第三,第四种转移的图示。

那么对于一次最长路,我们只需要 \(\forall A,B\) 选出 \(q[A][B]\) 中的最大值即可。建图跑 SPFA 即可。

在选出一次后,我们应该对于最长路径上的所有 \(x,y\) ,更新出其实际所连的 \(V\) 以达成懒惰删除的目的,因为 \(S\to V,V\to V,V\to T\) 的边权都及其依赖 \(x,y\) 的实际链接情况。

对于一条更新的连边 \(x\to V_i\),我们应该 \(\forall j\) 连边 \(V_i\to V_j\),记录相应边权 \(E(x,V_j)-E(x,V_i)\)

对于一条更新的连边 \(V_i\to y\),我们应该 \(\forall j\) 连边 \(V_j\to V_i\),记录相应边权 \(E(V_j,y)-E(V_i,y)\)

由于一次最多添加 \(3\times 4\times 5=60\) 条边,而一次SPFA的计算次数最大为 \(6\times 6^2=216\)

最后复杂度(大致估计常数) \(\mathcal O(36n+60n\log 60n)\),去掉常数后就是 \(\mathcal O(n\log n)\)

代码:

#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;
}
posted @ 2025-02-27 21:59  lupengheyyds  阅读(23)  评论(0)    收藏  举报