最大流

来源:互联网 发布:linux配置ntp客户端 编辑:程序博客网 时间:2024/04/27 17:47

压入重标法Push-relabel  algorithm(预流推进法Preflow-push method):

Push-relabel算法的流程如下:  

1 )我们先假定一个高度函数 h ( u ) ,他代表u点的高度,只有h ( u )比较高的点才能够将水流到h ( u )比较低的点;  

2 ) 在程序一开始的时候,让source node的高度是n ( node数) ,  其它点的高度都是 0 ,这样source node才有足够的高度可以流往其它地方 ;  

3 ) 然后, 让source node往其它所有跟他直接相邻的node ,都流水管宽度的水量 ( 流过去之后当然要计算剩下的网络情形,即计算 residual  edges(残留网络)

4 )对所有active node( 目前有水的 node )做 relabel(重标记)的动作:  在当某个node明明有水,但是他所连出去的所有对象的 h ( u ) 都比

他还高, 则让他的h ( u ) 增加为至少有一条水管可以流出去的量,也就是让这个有水的 active node的高度变成比他连往的”高度最小的 n o d e ”+l , ( 流过去之后还是要计算剩下的网络情形

5 )对所有可以做push(压入)动作的node做push的动作。  所谓的Push动作是指 : 当某个node有水,并且他有可以流出去的边, 且他刚好比可以流出去的那个点高度高一点点 ( 高度恰好比他高 1 ) ,那就把某个node 的水流过去,要流多少呢?以下两者取 mi n。  A:流出去的水管的量( 也就是说,这个active node的水量很多,  足够把这条水管塞满( 饱和) ,这个时候就叫做saturating Push)(饱和压入);B:某个 n o d e 现在的水量( 这个 n o d e的水量不足以把流出去的这个水管填满,称作non saturating Push(不饱和压入)  

6 )重复Relabel和Push的工作,一直到没有active node为止,此时从source node所流出的总流量( P r e f l o w) ,就是这个图的最大流量。  


例子:

POJ1459

Description

A power network consists of nodes (power stations, consumers and dispatchers) connected by power transport lines. A node u may be supplied with an amount s(u) >= 0 of power, may produce an amount 0 <= p(u) <= pmax(u) of power, may consume an amount 0 <= c(u) <= min(s(u),cmax(u)) of power, and may deliver an amount d(u)=s(u)+p(u)-c(u) of power. The following restrictions apply: c(u)=0 for any power station, p(u)=0 for any consumer, and p(u)=c(u)=0 for any dispatcher. There is at most one power transport line (u,v) from a node u to a node v in the net; it transports an amount 0 <= l(u,v) <= lmax(u,v) of power delivered by u to v. Let Con=Σuc(u) be the power consumed in the net. The problem is to compute the maximum value of Con.

An example is in figure 1. The label x/y of power station u shows that p(u)=x and pmax(u)=y. The label x/y of consumer u shows that c(u)=x and cmax(u)=y. The label x/y of power transport line (u,v) shows that l(u,v)=x and lmax(u,v)=y. The power consumed is Con=6. Notice that there are other possible states of the network but the value of Con cannot exceed 6.

Input

There are several data sets in the input. Each data set encodes a power network. It starts with four integers: 0 <= n <= 100 (nodes), 0 <= np <= n (power stations), 0 <= nc <= n (consumers), and 0 <= m <= n^2 (power transport lines). Follow m data triplets (u,v)z, where u and v are node identifiers (starting from 0) and 0 <= z <= 1000 is the value of lmax(u,v). Follow np doublets (u)z, where u is the identifier of a power station and 0 <= z <= 10000 is the value of pmax(u). The data set ends with nc doublets (u)z, where u is the identifier of a consumer and 0 <= z <= 10000 is the value of cmax(u). All input numbers are integers. Except the (u,v)z triplets and the (u)z doublets, which do not contain white spaces, white spaces can occur freely in input. Input data terminate with an end of file and are correct.

Output

For each data set from the input, the program prints on the standard output the maximum amount of power that can be consumed in the corresponding network. Each result has an integral value and is printed from the beginning of a separate line.

Sample Input

2 1 1 2 (0,1)20 (1,0)10 (0)15 (1)207 2 3 13 (0,0)1 (0,1)2 (0,2)5 (1,0)1 (1,2)8 (2,3)1 (2,4)7         (3,5)2 (3,6)5 (4,2)7 (4,3)5 (4,5)1 (6,0)5         (0)5 (1)2 (3)2 (4)1 (5)4

Sample Output

156
#include<iostream>#include<stdio.h>#include<string.h>#define SIZE 202#define INF 0xfffffffusing namespace std;int map[SIZE][SIZE]; //保存图int f[SIZE][SIZE]; //记录边(u,v)的流量int e[SIZE]; //余流int h[SIZE]; //高度int n,nc,np,m;int source,sink;void push(int u,int v) //压入操作{    int d=min(e[u],map[u][v]-f[u][v]); //选取余流和残余流量的最小值    f[u][v]+=d; //更新流与余流    f[v][u]=-f[u][v];//反向流用于向上游回退盈余的e[u],以便从上游其它路流向终点    e[u]-=d;    e[v]+=d;}bool relabel(int u){    int minh=INF,i;    for(i=0;i<n+2;i++)        if(map[u][i]>f[u][i]) minh=min(minh,h[i]); //当前流未超过容量 找到与u相邻的且高度最小的点    if(minh==INF) return false; //残留网络中无从u出发的路    h[u]=minh+1; //修改u的高度+1    for(i=0;i<n+2;i++)    {        if(e[u]==0) break; //无余流 不需再次压入        if(h[i]==minh&&map[u][i]>f[u][i]) //当高度与最小高度相等且流比容量小时进行push操作            push(u,i);    }    return true;}void init_preflow(){    int i;    memset(h,0,sizeof(h));    memset(e,0,sizeof(e));    h[source]=n+2; //h[sink]=0;可省略    for(i=0;i<n+2;i++)    {        if(map[source][i]==0) continue;        f[source][i]=map[source][i];        f[i][source]=-f[source][i];        e[i]=map[source][i];        e[source]=-map[source][i];    }}void push_relabel(){    init_preflow(); //初始化    bool flag=true; //表示是否还能进行relabel操作    int i;    while(flag) //还可以进行重标记操作    {        flag=false;        for(i=0;i<n;i++)            if(e[i]>0) flag=flag||relabel(i);    }}int main(){    int i;    int x,y,value;    while(scanf("%d%d%d%d",&n,&np,&nc,&m)!=EOF)    {        memset(map,0,sizeof(map));        memset(f,0,sizeof(f));        source=n; sink=n+1;//增加超级源点和超级汇点        while(m--)        {            scanf(" (%d,%d)%d",&x,&y,&value);            map[x][y]=value;        }        for(i=0;i<np;i++)        {            scanf(" (%d)%d",&x,&value);            map[source][x]=value;        }        for(i=0;i<nc;i++)        {            scanf(" (%d)%d",&x,&value);            map[x][sink]=value;        }        push_relabel();        printf("%d\n",e[sink]);    }    return 0;}





0 0
原创粉丝点击