HDU 6142 Jedi Council(最小割-Dinic)

来源:互联网 发布:h5页面源码下载 编辑:程序博客网 时间:2024/05/23 12:06

Description

n个值wi,每个值要么是w要么是w,给出q个限制,限制有三种:

x y 0wxwy

x y 1wx=wy

x y 2wx<wy

要求给出满足上述条件的赋值使得O=i=1nwi+i=1pHi最小,输出最小值

其中Hi=ai|wxiwyi|+bi|wyiwzi|+ci|wziwxi|+di(wxiwyi)+ei(wyiwzi)+fi(wziwxi)

Input

第一行一整数T表示用例组数,每组用例首先输入四个整数n,w,p,q,之后p行每行九个整数xi,yi,zi,ai,bi,ci,di,ei,fi,最后q行每行三个整数x,y,op表示一组限制

(1n500,0w106,1p,q,ai,bi,ci,di,ei,fi1000,1xi,yi,zi,x,yn

Output

输出O的最小值

Sample Input

1
3 1 1 1
1 2 3 1 1 1 1 1 1
1 2 2

Sample Output

3

Solution

|ab|+(ab)=2max{ab,0}

Hi=2aimax{wxiwyi,0}+2bimax{wyiwzi,0}+2cimax{wziwxi,0}

+((diai)(fici))wxi+((eibi)(diai))wyi+((fici)(eibi))wzi

最小割的另一种解释:令源点S0,汇点T1,给每个点i赋一个值xi=0xi=1,那么最小割本质上是把n个点分成两个集合,使得花费u,vmax{xvxu}f(u,v)最小,其中f(u,v)表示uv的流量

本题类似的把n个点分成两个集合,一个集合赋值为w,另一个集合赋值为w,把所有点的点权加上w,则点的值变成为02w,把单位点权取为w,最后算出的值乘上w即为答案,系数2体现在容量上即可

一.对于形如amax{wxwy}的项从yx建容量为2a的边即可

二.对于形如awx的项,首先由于wx都被加上了w,所以先在答案中减掉a

1.当a>0时,aw=amax{wx0,0},从源点向x建容量为2a的边

2.当a<0时,aw=amax{1wx,0}+a,从x向汇点容量为建2a的边,多加的2a要在答案中减掉

三.对于限制x y op

1.当op=0时,wxwy,说明不能出现wx>wy的情况,从yx建容量为无穷的边即可

2.当op=1时,wx=wy,即为wxwywywx,从xy 、从yx均建容量为无穷的边

3.当op=2时,wx<wy,即为wx0wy1,从源点向x 、从x向汇点均建容量为无穷的边

Code

#include<cstdio>#include<iostream>#include<cstring>#include<algorithm>#include<cmath>#include<vector>#include<queue>#include<map>#include<set>#include<ctime>using namespace std;typedef long long ll;#define maxn 505 #define maxm 20005#define INF 0x3f3f3f3fint head[maxn],cur[maxn],d[maxn],st[maxm],s,e,no;//s为源点,e为汇点,n为点数,no为边数 struct point{    int u,v,flow,next;    point(){};    point(int x,int y,int z,int w):u(x),v(y),next(z),flow(w){};}p[maxm];void add(int x,int y,int z)//从x到y建容量为z的边 {    p[no]=point(x,y,head[x],z);//前向弧,标号为偶     head[x]=no++;    p[no]=point(y,x,head[y],0);//后向弧,标号为奇     head[y]=no++;}void init()//初始化 {    memset(head,-1,sizeof(head));    no=0;}bool bfs(){    int i,x,y;    queue<int>q;    memset(d,-1,sizeof(d));    d[s]=0;     q.push(s);    while(!q.empty())    {        x=q.front();            q.pop();        for(i=head[x];i!=-1;i=p[i].next)        {            if(p[i].flow&& d[y=p[i].v]<0)            {                d[y]=d[x]+1;                if(y==e)                        return true;                q.push(y);            }        }    }    return false;}int dinic()//最大流 {    int i,loc,top,x=s,nowflow,maxflow=0;    while(bfs())    {        memcpy(cur,head,sizeof(head));        top=0;        while(true)        {            if(x==e)            {                nowflow=INF;                for(i=0;i<top;i++)                {                    if(nowflow>p[st[i]].flow)                    {                        nowflow=p[st[i]].flow;                        loc=i;                    }                }                for(i=0;i<top;i++)                {                    p[st[i]].flow-=nowflow;                    p[st[i]^1].flow+=nowflow;                }                maxflow+=nowflow;                top=loc;                    x=p[st[top]].u;            }            for(i=cur[x];i!=-1;i=p[i].next)                if(p[i].flow&&d[p[i].v]==d[x]+1)                     break;            cur[x]=i;            if(i!=-1)            {                st[top++]=i;                x=p[i].v;            }            else             {                if(!top)                        break;                d[x]=-1;                x=p[st[--top]].u;            }        }    }    return maxflow;}int T,n,W,P,Q,num[maxn]; int main(){    scanf("%d",&T);    while(T--)    {        scanf("%d%d%d%d",&n,&W,&P,&Q);        s=0,e=n+1;        init();        for(int i=1;i<=n;i++)num[i]=1;        while(P--)        {            int x,y,z,a,b,c,d,e,f;            scanf("%d%d%d%d%d%d%d%d%d",&x,&y,&z,&a,&b,&c,&d,&e,&f);            add(y,x,4*a),add(z,y,4*b),add(x,z,4*c);            num[x]+=(d-a)-(f-c),num[y]+=(e-b)-(d-a),num[z]+=(f-c)-(e-b);        }        int ans=0;        for(int i=1;i<=n;i++)            if(num[i]>0)ans-=num[i],add(s,i,2*num[i]);            else if(num[i]<0)ans+=num[i],add(i,e,-2*num[i]);        while(Q--)        {            int x,y,op;            scanf("%d%d%d",&x,&y,&op);            if(op==0)add(y,x,INF);            else if(op==1)add(x,y,INF),add(y,x,INF);            else add(s,x,INF),add(y,e,INF);        }        ans+=dinic();        printf("%I64d\n",(ll)ans*W);    }    return 0;}
原创粉丝点击