POJ 1459--Power Network(三种方法求最大流)

来源:互联网 发布:mastercam9.1三维编程 编辑:程序博客网 时间:2024/05/22 02:18

  • 根据题意,新建一个超级节点,所有发电站的流量由此节点发出,新建一个超级汇点,所有节点 使用的流量都流到此节点。 然后采用最大流的各种方法求解。
  1. 不管用ford——fulkerson方法还是推送重贴标签,首先都不用管自环,显然一个最大流是不会包括自环的,自环只会减少流量。然后反向边也不需要如算法导论中加入另外的点进行处理。为了减少内存,直接用容量的减少代表流量的增加,正向边容量减少多少,正向流 量就增加多少,同时增加相应的反向容量,意思就是说反向的能允许的流量增加,而如果接下来的操作反向容量减少,也就是有反向的流量,也即是正向流量的减少,不管正向反向流量都可增可少,但是注意的是实际上最大流只会有一个方向的流量,但是可以等效为上述操作。直至所有增广路径的残余流量都是0。-------------ford——fulkerson
  2. push——relabel:此算法较难理解,初始化后若一个点有溢出,并且其所有能流入的点(因为在构图里面允许反向边,所以不用像算法导论里面允许一个反向的流量作为残余边 来减少流量,而本算法在对反向容量增加时可以达到同样的效果。所以只要capacity[u][v]>0就说明还有残余流量)高度均大于等于它,就对此点更新高度。若此点高度等于其能流入的点高度加1,则对此边推入操作。因为在满足溢出,可流入条件下,推入和重贴标签是互斥的,可以优化。
  3. Dinic:  首先BFS分层,为了构造一个有向无环图,当BFS无法到达汇点时,已达最大流。然后对上图作DFS,类似于二分匹配,当DFS到最后一点,其不能向下迭代但是又不是汇点则将此点标记不再走。当到达汇点回溯时,只回溯到路径最小边(u,v),因为显然从u点还可能向下找增广路径,可继续使用u点以前多余的流量,所以要对每点设置一个总增广值sumAug,记录此点能到达的所有增广路径使用的流量,然后再从此点回溯。

ford-fulkerson:
#include<iostream>#include<cstdio>#include<queue>#include<cstring>using namespace std;#define min(x,y) (x>y?y:x)#define INF   (0X7F7F)#define maxN  105short capacity[maxN][maxN];short nodeNum;short start;short dest;int maxFlow(){    short fa[maxN];    short minPathFlow[maxN];    queue<short> q;    short now,i,tmpFlow,son;    int maxFlow = 0;    while(1)    {        memset(fa,127,sizeof(short)*(nodeNum+2));        memset(minPathFlow,127,sizeof(short)*(nodeNum+2));        q.push(start);        while(!q.empty())              //寻找始终点最短路径        {            now = q.front();            q.pop();            for(i = 0;i <= nodeNum;i++)            {                tmpFlow = capacity[now][i];                if(fa[i] == INF&&tmpFlow > 0)                {                if(i == dest)                {                    minPathFlow[dest] = min(minPathFlow[now],tmpFlow);                    fa[dest] = now;           //并查集                    break;                }                else                {                    fa[i] = now;                    minPathFlow[i] = min(minPathFlow[now],tmpFlow);                    q.push(i);                }                }            }        }        if(minPathFlow[dest] != INF)          //更新流量        {            maxFlow += minPathFlow[dest];            son = dest;            while(son != start)            {                capacity[fa[son]][son] -= minPathFlow[dest];                capacity[son][fa[son]] += minPathFlow[dest];                son = fa[son];            }        }        else            break;    }    cout<<maxFlow<<endl;    return 0;}int main(){    char tmpCh;    short u,v,cmax,powerNum,consumerNum,lineNum;    while(scanf("%hd%hd%hd%hd",&nodeNum,&powerNum,&consumerNum,&lineNum)!=EOF)    {        memset(capacity,0,sizeof(short)*(maxN*maxN));        while(lineNum--)        {            cin>>tmpCh>>u>>tmpCh>>v>>tmpCh>>cmax;                capacity[u][v] = cmax;        }        start = nodeNum+1;        dest = nodeNum;        while(powerNum--)        {            cin>>tmpCh>>u>>tmpCh>>cmax;            capacity[start][u] = cmax;        }        while(consumerNum--)        {            cin>>tmpCh>>u>>tmpCh>>cmax;            capacity[u][dest] = cmax;        }        maxFlow();    }    return 0;}

push-relabel to front:
#include<iostream>#include<cstdio>#include<cstring>using namespace std;#define maxN 105#define min(x,y)   (x>y?y:x)#define INF  (0x7F7F)int capacity[maxN][maxN];short nodeNum;short start,dest;short height[maxN];int exceFlow[maxN];struct node{    short x;    node *next;    node *prev;}*head;bool push(short u,short v){    int minFlow = min(exceFlow[u],capacity[u][v]);    capacity[u][v] -= minFlow;    capacity[v][u] += minFlow;    exceFlow[u] -= minFlow;    exceFlow[v] += minFlow;    return true;}bool relabel(short u){    short i;    short minHeight = INF;    for(i = 0;i < nodeNum;i++)    {        if(capacity[u][i] > 0&&height[u] <= height[i])            minHeight = min(minHeight,height[i]);    }    height[u] = minHeight+1;    return true;}int discharge(short u){    short v = 0;    while(exceFlow[u] > 0)    {        if(v == nodeNum)        {            relabel(u);            v = 0;        }        else if(capacity[u][v] > 0&&height[u] == height[v]+1)        {            push(u,v);        }        else        {            v++;        }    }    return 1;}int moveToHead(node *tmp){    if(tmp->prev != NULL)    {        if(tmp->next != NULL)        {            tmp->prev->next = tmp->next;            tmp->next->prev = tmp->prev;        }        else        {            tmp->prev->next = NULL;        }        tmp->next = head;        head->prev = tmp;        head = tmp;        head->prev = NULL;    }    return 1;}int relabelToFront(){    short i,u;    bool IsMax = false;    short oldHeight;    bool IsRelabel;    /*****Initialize preflow******/    memset(height,0,sizeof(short)*(nodeNum));    height[start] = nodeNum;    memset(exceFlow,0,sizeof(int)*(nodeNum));    for(i = 0;i < nodeNum-2;i++)    {        if(capacity[start][i] > 0)        {            exceFlow[i] = capacity[start][i];            exceFlow[start] -= capacity[start][i];            capacity[i][start] = capacity[start][i];            capacity[start][i] = 0;        }    }    /*****Init List*********/    node *tmp;    head = NULL;    for(i = 0;i < nodeNum-2;i++)    {        tmp = new node;        tmp->x = i;        tmp->next = head;        if(head != NULL)            head->prev = tmp;        head = tmp;        head->prev = NULL;    }    tmp = head;    while(tmp != NULL)    {        u = tmp->x;        oldHeight = height[u];        discharge(u);        if(height[u] > oldHeight)        {            moveToHead(tmp);        }        tmp = tmp->next;    }    delete[] tmp;    delete[] head;    cout<<exceFlow[dest]<<endl;    return 1;}int main(){    short powerNum,consumerNum,lineNum;    int u,v,cmax;    char tmpCh;    while(cin>>nodeNum>>powerNum>>consumerNum>>lineNum)    {        memset(capacity,0,sizeof(int)*(maxN*maxN));        while(lineNum--)        {            cin>>tmpCh>>u>>tmpCh>>v>>tmpCh>>cmax;            if(u != v)            capacity[u][v] = cmax;        }        nodeNum += 2;        start = nodeNum-1;        dest = nodeNum-2;        while(powerNum--)        {            cin>>tmpCh>>u>>tmpCh>>cmax;            capacity[start][u] = cmax;        }        while(consumerNum--)        {            cin>>tmpCh>>u>>tmpCh>>cmax;            capacity[u][dest] = cmax;        }        relabelToFront();    }    return 0;}

Dinic:
#include<iostream>#include<cstdio>#include<cstring>using namespace std;#define maxN 105#define min(x,y)   (x>y?y:x)#define INF  (0x7F7F)int capacity[maxN][maxN];short nodeNum;short start,dest;short height[maxN];int maxFlow;int Aug(short u,int minFlow){    short i;    int tmpFlow,tmpAug;    int sumAug = 0;    if(u == dest)    {        maxFlow += minFlow;        return minFlow;           //返回增广路径中最小容量,能增加的最大流量    }    for(i = 1;i < nodeNum;i++)    {        if(capacity[u][i] > 0&&height[i] == height[u]+1)        {            tmpFlow = min(minFlow,capacity[u][i]);            tmpAug = Aug(i,tmpFlow);            sumAug += tmpAug;               //从u点出发可能有不同的增广路径,将所有路径的容量保存在sumAug            if(tmpAug)            {                capacity[u][i] -= tmpAug;                capacity[i][u] += tmpAug;                if(capacity[u][i] != 0)      //若流量减为0,即寻找的增广路径的最小容量在此点,则从此点父节点再往下增广,反之直接返回找到路径容量最小点                return sumAug;                else                {                    minFlow -= tmpAug;        //再往下增广时,能允许的流量减少                }            }            else            {                height[i] = INF;             //从i点已无增广路径,将此点锁定不被访问            }        }    }    return sumAug;}int BFS(){    short q[maxN];    short now,rear,i;    q[now = rear = 0] = start;            memset(height,127,sizeof(short)*(nodeNum));    height[start] = 0;    while(now <= rear)    {        for(i = 1;i < nodeNum;i++)        {            if(capacity[q[now]][i] > 0&&height[i] == INF)            {                height[i] = height[q[now]]+1;            //可流的两点高度相差一,高度相差一不一定可流                q[++rear] = i;                if(i == dest)                    return 1;            }        }        now++;    }    return 0;}int Dinic(){    maxFlow = 0;    while(BFS())    {        Aug(start,INF);    }    cout<<maxFlow<<endl;    return 1;}int main(){    short powerNum,consumerNum,lineNum;    int u,v,cmax;    char tmpCh;    while(cin>>nodeNum>>powerNum>>consumerNum>>lineNum)    {        memset(capacity,0,sizeof(int)*(maxN*maxN));        while(lineNum--)        {            cin>>tmpCh>>u>>tmpCh>>v>>tmpCh>>cmax;            if(u != v)            capacity[++u][++v] = cmax;        }        nodeNum += 2;        start = 0;        dest = nodeNum-1;        while(powerNum--)        {            cin>>tmpCh>>u>>tmpCh>>cmax;            capacity[start][++u] = cmax;        }        while(consumerNum--)        {            cin>>tmpCh>>u>>tmpCh>>cmax;            capacity[++u][dest] = cmax;        }        Dinic();    }    return 0;}



0 0
原创粉丝点击