【题目描述】
有n个变量w[1]~w[n],每个变量可以取W或-W。
有p个式子,形如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])。
有q个条件,形如w[x]<=w[y]或w[x]=w[y]或w[x]
【输入数据】
第一行一个整数t表示数据组数。
每组数据第一行四个整数n,W,p,q表示节点数。
接下来p行每行九个整数xi,yi,zi,ai,bi,ci,di,ei,fi。
接下来q行每行三个整数x,y,r。
r=0表示w[x]<=w[y];r=1表示w[x]=w[y];r=2表示w[x]
【输出数据】
每组数据输出一行一个整数表示sigma(wi)+sigma(Hi)的最小值。
【样例输入】
1
3 1 1 1
1 2 3 1 1 1 1 1 1
1 2 2
【样例输出】
3
【数据范围】
对于30%的数据,n<=15,p,q<=20。
对于100%的数据,t<=10,n<=500,p,q<=1000。
Solution
好久没打二元关系了,刚好用这题想起来了二元关系这个东西
注意到与d,e,f有关的可以直接乘进去,所以可以直接当成本身的全职,而前面a,b,c是有绝对值的,处理起来麻烦一点
由于w只有正负两种取值,可以发现,只有当取值互为相反数时才有用
所以不管它x,y,z,全部分成xy,xz,yz分别做
为了方便,只讨论xy,后两个一样
现在考虑x,y
首先源点向x连权值为(d-f)w+w,x向汇点连-(d-f)w-w
表示割掉源点边表示选正,割掉汇点边表示选负
对于y类似的
源点向x连权值为(e-d)w+w,x向汇点连-(e-d)w-w
然后x向y连双向边,边权为2wa,即两个分别归s集和y集,即选的相反,则需要割掉这条边
接下来考虑那几个限制
源点为S,汇点为T
限制x
Code
当时脑抽还分了点,实际不用
#include<cstdio>
#include<cstring>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define N 101000
#define INF 2147483647000000
#define DA 100000000000
#define M 1010
#define ll long long
#define cl(a) memset(a,0,sizeof(a))
using namespace std;
int S,T,n,m,p,q,last[M],next[N],to[N],tot=1,bz[M],d[M];
ll date[N],v[M],v0[M],v1[M],va[M][M],ans=0;
void putin(int x,int y,ll z)
{
next[++tot]=last[x];last[x]=tot;to[tot]=y;date[tot]=z;
next[++tot]=last[y];last[y]=tot;to[tot]=x;date[tot]=0;
// printf("%d %d %d\n",x,y,z);
}
bool bfs()
{
cl(bz);
int he=0,ta=1;d[1]=S;bz[S]=1;
while(he<ta)
{
int x=d[++he];
for(int i=last[x];i;i=next[i])
if(date[i]&&!bz[to[i]]) bz[to[i]]=bz[x]+1,d[++ta]=to[i];
}
return bz[T];
}
ll dfs(int x,ll t)
{
if(x==T) return t;
ll jy=0;
for(int i=last[x];i;i=next[i])
if(date[i])
{
int y=to[i];if(bz[y]!=bz[x]+1) continue;
ll qq=dfs(y,min(t,date[i]));
date[i]-=qq;date[i^1]+=qq;jy+=qq;t-=qq;
if(t==0) return jy;
}
if(jy==0) bz[x]=-1;
return jy;
}
int main()
{
freopen("variable.in","r",stdin);
freopen("variable.out","w",stdout);
int ac;scanf("%d",&ac);
while(ac--)
{
cl(last);tot=1;cl(va);cl(v);cl(v0);cl(v1);ans=0;
scanf("%d%d%d%d",&n,&m,&p,&q);
S=n+n+1;T=S+1;
fo(i,1,p)
{
ll x,y,z,a,b,c,d,e,f;
scanf("%lld%lld%lld%lld%lld%lld%lld%lld%lld",&x,&y,&z,&a,&b,&c,&d,&e,&f);
v[x]+=d-f;v[y]+=e-d;v[z]+=f-e;
va[x][y]+=a*m*2;va[y][x]+=a*m*2;
va[y][z]+=b*m*2;va[z][y]+=b*m*2;
va[x][z]+=c*m*2;va[z][x]+=c*m*2;
}
fo(i,1,q)
{
int x,y,z;scanf("%d%d%d",&x,&y,&z);
if(z==0)
{
va[y][x]+=INF;
}
if(z==1)
{
va[x][y]+=INF;
va[y][x]+=INF;
}
if(z==2)
{
v0[x]+=INF;
v1[y]+=INF;
}
}
fo(i,1,n)
{
putin(S,i,m+m*v[i]+v0[i]+DA),putin(i+n,T,-m-m*v[i]+v1[i]+DA),putin(i,i+n,INF);
fo(j,1,n) if(va[i][j]!=0) putin(i,j+n,va[i][j]);
}
while(bfs()) ans+=dfs(S,INF);
printf("%lld\n",ans-DA*n);
}
}