Problem
Problem Description
有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]
Input
第一行一个整数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]
Output
每组数据输出一行一个整数表示sigma(wi)+sigma(Hi)的最小值。
Sample
Sample Input
1
3 1 1 1
1 2 3 1 1 1 1 1 1
1 2 2
Sample Output
3
Data Size
对于30%的数据,n<=15,p,q<=20。
对于100%的数据,t<=10,n<=500,p,q<=1000。
Solution
又是二元关系……
然而我连最小割都没有看出来,吃枣药柜。
二元关系——从入门到放弃
d,e,f的w可以直接乘起来,作为本身的权值。
对于a,b,c,我们对x,y进行讨论。我们设割源点为正数,割汇点为负数
那么源点向x连权值为(d-f)w+w,x向汇点连-(d-f)w-w
对于y就是±(e-d+1)w,对于z就是±(f-e+1)w
然后x向y连双向边,边权为2aw,即两个分别归s集和y集,即选的相反,则需要割掉这条边
其次,对于另外q个限制条件。
对于限制0,x向y连INF
对于限制1,x和y互连INF
对于限制2,s向y连INF,x向t连INF
Code
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
using namespace std;
typedef long long ll;
const ll INF=1ll<<60;
const int maxn=1010,maxm=100010;
struct data{
int v;ll w;int nxt;
}edge[maxm];
int z,ep,s,t,head[maxn],cur[maxn],dis[maxn],cnt[maxn];
ll ans,tmp,w;
queue<int> q;
inline ll min(ll x,ll y){return x<y?x:y;}
inline void insert(int u,int v,ll w)
{
edge[++ep]=(data){v,w,head[u]};head[u]=ep;
}
void input()
{
static int n,p,q,x,y,z,a,b,c,d,e,f;
scanf("%d%lld%d%d",&n,&w,&p,&q);
ep=-1;ans=0;s=n+1;t=n+2;
memset(cnt,0,sizeof(cnt));
memset(head,0xff,sizeof(head));
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);
cnt[x]+=d-f;cnt[y]+=e-d;cnt[z]+=f-e;
insert(x,y,a<<1);insert(y,x,a<<1);
insert(y,z,b<<1);insert(z,y,b<<1);
insert(x,z,c<<1);insert(z,x,c<<1);
}
for(int i=1;i<=n;i++) cnt[i]++;
for(int i=1;i<=n;i++)
{
if(cnt[i]>0)
ans-=cnt[i],insert(i,t,cnt[i]<<1),insert(t,i,0);
else if(cnt[i]<0)
ans+=cnt[i],insert(s,i,-(cnt[i]<<1)),insert(i,s,0);
}
for(int i=1;i<=q;i++)
{
scanf("%d%d%d",&x,&y,&z);
if(z==1)
insert(x,y,INF),insert(y,x,INF);
else if(z==2)
insert(x,t,INF),insert(t,x,0),insert(s,y,INF),insert(y,s,0);
else
insert(x,y,INF),insert(y,x,0);
}
}
int bfs(int s,int t)
{
while(!q.empty()) q.pop();
memset(dis,0,sizeof(dis));
dis[s]=1;
q.push(s);
while(!q.empty())
{
int x=q.front();
q.pop();
for(int i=head[x];~i;i=edge[i].nxt)
if(edge[i].w&&!dis[edge[i].v])
{
dis[edge[i].v]=dis[x]+1;
q.push(edge[i].v);
}
}
return dis[t];
}
ll dfs(int u,int t,ll flow)
{
if(u==t) return flow;
ll rest=0,tmp;
for(int &i=cur[u];~i;i=edge[i].nxt)
if(dis[edge[i].v]==dis[u]+1&&edge[i].w)
{
tmp=dfs(edge[i].v,t,min(flow-rest,edge[i].w));
rest+=tmp;edge[i].w-=tmp;edge[i^1].w+=tmp;
if(rest==flow) break;
}
if(!rest) dis[u]=-1;
return rest;
}
int main()
{
freopen("variable.in","r",stdin);
freopen("variable.out","w",stdout);
scanf("%d",&z);
while(z--)
{
input();
while(bfs(s,t))
{
memmove(cur,head,sizeof(cur));
while(tmp=dfs(s,t,INF))
ans+=tmp;
}
printf("%lld\n",ans*w);
}
return 0;
}