变量

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;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值