雅礼集训1.2 T2变量

该文章介绍了一种利用最大流算法解决含有绝对值的线性表达式优化问题的方法。题目中涉及n个变量,每个变量可取-W到W的值,有p个式子和q个条件约束。通过建立网络流图并处理绝对值项,转换为求解最小割问题,最终计算总和的最小值。算法的时间复杂度与最大流算法相关。

题目大意

nnn个变量w[1],w[2],…,w[n]w[1],w[2],\dots,w[n]w[1],w[2],,w[n],每个变量可以取−W-WWWWW

ppp个式子,形如

Hi=ai∣w[xi]−w[yi]∣+bi∣w[yi]−w[zi]∣+ci∣w[zi]−w[xi]∣+di(w[xi]−w[yi]),ei(w[yi]−w[zi])+fi(w[zi]−w[xi])H_i=a_i|w[x_i]-w[y_i]|+b_i|w[y_i]-w[z_i]|+c_i|w[z_i]-w[x_i]|+d_i(w[x_i]-w[y_i]),e_i(w[y_i]-w[z_i])+f_i(w[z_i]-w[x_i])Hi=aiw[xi]w[yi]+biw[yi]w[zi]+ciw[zi]w[xi]+di(w[xi]w[yi]),ei(w[yi]w[zi])+fi(w[zi]w[xi])

qqq个条件,每个条件表示为x,y,rx,y,rx,y,r

  • r=0r=0r=0表示w[x]≤w[y]w[x]\leq w[y]w[x]w[y]
  • r=1r=1r=1表示w[x]=w[y]w[x]=w[y]w[x]=w[y]
  • r=2r=2r=2表示w[x]<w[y]w[x]<w[y]w[x]<w[y]

∑w[i]+∑Hi\sum w[i]+\sum H_iw[i]+Hi的最小值。保证存在方案。

1≤t≤101\leq t\leq 101t101≤n≤5001\leq n\leq 5001n5001≤p,q≤10001\leq p,q\leq 10001p,q10001≤W≤1061\leq W\leq 10^61W1060≤ai,bi,ci,di,ei,fi≤10000\leq a_i,b_i,c_i,d_i,e_i,f_i\leq 10000ai,bi,ci,di,ei,fi1000


题解

我们可以把题面看作变量选−1-11111,最后再乘上WWW

这题要用用最大流。对于每个变量,建一个点iii,源点sssiii连边,iiittt连边。割这两条边分别表示取−1-11111

ppp个式子中,我们把不带绝对值的拆开,分别加到各个点的系数viv_ivi上。对于带绝对值的,如ai∣w[xi]−w[yi]∣a_i|w[x_i]-w[y_i]|aiw[xi]w[yi],则在xix_ixiyiy_iyi之间连一条流量为2ai2a_i2ai的无向边。

对于qqq个条件,w[x]<w[y]w[x]<w[y]w[x]<w[y]等价于w[x]=−1,w[y]=1w[x]=-1,w[y]=1w[x]=1,w[y]=1;如果w[x]=w[y]w[x]=w[y]w[x]=w[y],就在w[x]w[x]w[x]w[y]w[y]w[y]之间连一条流量为正无穷的边;如果w[x]≤w[y]w[x]\leq w[y]w[x]w[y],就从aaabbb连一条流量为正无穷的有向边。

因为存在负边权,所以我们需要把所有sssiiiiiittt的边加上一个小于正无穷的值ptptpt,然后在最后减去n×ptn\times ptn×pt即可。

跑一遍最大流求最小割,然后减去n×ptn\times ptn×pt,再乘上WWW即可。

时间复杂度为O(t×maxflow(n,n+p+q))O(t\times maxflow(n,n+p+q))O(t×maxflow(n,n+p+q))

code

#include<bits/stdc++.h>
using namespace std;
int T,n,ww,p,q,tot,s,t,cs[20005],l[20005],r[20005],d[20005],vd[20005];
long long ans,w[20005],v[20005];
long long inf=1e16,pt=1e10;
void add(int xx,int yy,long long zz){
	l[++tot]=r[xx];cs[tot]=yy;r[xx]=tot;w[tot]=zz; 
}
long long aug(int i,long long augco){
	if(i==t) return augco;
	long long augc=augco,dl=0;
	int md=n-1;
	for(int u=r[i];u;u=l[u]){
		int j=cs[u];
		if(w[u]>0){
			if(d[i]==d[j]+1){
				dl=min(augc,w[u]);
				dl=aug(j,dl);
				w[u]-=dl;
				w[u^1]+=dl;
				augc-=dl;
				if(d[s]>=n) return augco-augc;
				if(!augc) break;
			}
			if(md>d[j]) md=d[j];
		}
	}
	if(augco==augc){
		--vd[d[i]];
		if(!vd[d[i]]) d[s]=n;
		d[i]=md+1;
		++vd[d[i]];
	}
	return augco-augc;
}
void sap(){
	memset(d,0,sizeof(d));
	vd[0]=n;
	while(d[s]<n) ans+=aug(s,inf);
}
int main()
{
	scanf("%d",&T);
	while(T--){
		scanf("%d%d%d%d",&n,&ww,&p,&q);
		tot=1;
		memset(r,0,sizeof(r));
		for(int i=1;i<=n;i++) v[i]=1;
		int x,y,z,a,b,c,d,e,f;
		s=n+1;t=n+2;
		for(int i=1;i<=p;i++){
			scanf("%d%d%d%d%d%d%d%d%d",&x,&y,&z,&a,&b,&c,&d,&e,&f);
			add(x,y,2*a);add(y,x,2*a);
			add(y,z,2*b);add(z,y,2*b);
			add(z,x,2*c);add(x,z,2*c);
			v[x]+=d-f;
			v[y]+=e-d;
			v[z]+=f-e;
		}
		for(int i=1;i<=q;i++){
			scanf("%d%d%d",&x,&y,&z);
			if(z==0){
				add(x,y,inf);add(y,x,0);
			}
			else if(z==1){
				add(x,y,inf);add(y,x,inf);
			}
			else{
				add(x,t,inf);add(t,x,0);
				add(s,y,inf);add(y,s,0);
			}
		}
		for(int i=1;i<=n;i++){
			add(s,i,-v[i]+pt);add(i,s,0);
			add(i,t,v[i]+pt);add(t,i,0);
		}
		ans=-n*pt;
		n+=2;
		sap();
		printf("%lld\n",ans*ww);
	}
	return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值