POJ 3469 - Dual Core CPU(Dinic最大流)

来源:互联网 发布:网络推手的盈利模式 编辑:程序博客网 时间:2024/06/16 22:02

【题意】

有N个任务,A与B两个核心,任务i若在A上执行需代价Ai,在B上执行需代价Bi

还有M个特殊关系,表示若任务a与任务b不在同一机器上执行,需额外代价C

第一行输入N<=20000,M<=200000

接下来N行是Ai Bi

接下来M行是特殊关系a b

求完成所有任务最小代价

 

【题解】

网络流建模,超级源sr到每个任务i有容量为Ai的单向边,每个任务i到超级汇dr有容量为Bi的单向边,特殊对a b之间有双向边容量为C,最小割即为答案。

有最大流最小割定理可求最大流。

使用Dinic+多路增广(必选)+当前弧(可选)

根据本蒟蒻的代码实验,裸Dinic会T,加多路增广4200ms,加当前弧3.6ms,所以多路增广很关键,具体实现就是dfs时把他上一个点传过来的可增广流量尽量用完,并且如果耗尽了自己的的出口残量,在这次的层次图中就不在尝试这个点。具体见代码。

还有,这个代码比较奇葩,我是从汇点向源点搜的,但是搜出来的路还是从sr到dr增广,看代码就明白。

#include<cstdio>#include<cstdlib>#include<cstring>#include<climits>#include<iostream>#include<vector>#include<algorithm>using namespace std;const int NMAX=20000,MMAX=200000,VMAX=NMAX+100,EMAX=(NMAX*2+MMAX)*2+100;struct Edge{    int h,t,f;    Edge *ne,*re;};struct EList{    Edge *head;    static void next(Edge* &p){        p=p->ne;    }    static void uniteRev(){        pool[cnt-1].re=pool+cnt-2;        pool[cnt-2].re=pool+cnt-1;    }    void push(int t,int f){        pool[cnt].t=t;        pool[cnt].f=f;        pool[cnt].ne=head;        head=pool+cnt++;    }    static Edge pool[EMAX];    static int cnt;};int EList::cnt;Edge EList::pool[EMAX];EList eg[VMAX];namespace dinic{    int depg[VMAX],sr,dr;    Edge *nh[VMAX];    bool bfs(){        static int que[VMAX];        memcpy(nh,eg,(dr+1)*sizeof(EList));//当前弧预处理        int head=0,rear=0;        memset(depg,-1,(dr+1)*sizeof(int));        for(depg[que[rear++]=sr]=0;head!=rear;){            int now=que[head++];            for(Edge *it=eg[now].head;it;EList::next(it))             if(!~depg[it->t] && it->f) depg[que[rear++]=it->t]=depg[now]+1;        }        return depg[dr]!=-1;    }    int dfs(int x,int f){        static Edge *head[VMAX];        if(depg[x]==0) return f;//找到源点        int ft,w=0;        for(Edge *&it=nh[x];it;EList::next(it)){            if(depg[x]-1==depg[it->t] && it->re->f)             if(ft=dfs(it->t,min(f-w,it->re->f))){                it->re->f-=ft;                it->f+=ft;                w+=ft;             }            if(w==f) break;//如果可增广流量耗尽,则退出        }        if(!w) depg[x]=-1;//如果不可增广,即出口残量耗尽,则不再访问此点        return w;    }    long long calc(int _sr,int _dr){        long long res=0;        sr=_sr;dr=_dr;        for(;bfs();)         for(int ft;ft=dfs(dr,INT_MAX);) res+=ft;        return res;    }}int main(){    freopen("in.txt","r",stdin);    for(int n,m;~scanf("%d%d",&n,&m);){        EList::cnt=0;        memset(eg,0,sizeof eg);        for(int i=0;i<n;i++){            int a,b;            scanf("%d%d",&a,&b);            eg[0].push(i+1,a);            eg[i+1].push(0,0);            EList::uniteRev();            eg[i+1].push(n+1,b);            eg[n+1].push(i+1,0);            EList::uniteRev();        }        for(int i=0;i<m;i++){            int h,t,f;            scanf("%d%d%d",&h,&t,&f);            eg[h].push(t,f);            eg[t].push(h,f);            EList::uniteRev();        }       printf("%lld\n",dinic::calc(0,n+1));    }    return 0;}