- 根据题意,新建一个超级节点,所有发电站的流量由此节点发出,新建一个超级汇点,所有节点 使用的流量都流到此节点。 然后采用最大流的各种方法求解。
- 不管用ford——fulkerson方法还是推送重贴标签,首先都不用管自环,显然一个最大流是不会包括自环的,自环只会减少流量。然后反向边也不需要如算法导论中加入另外的点进行处理。为了减少内存,直接用容量的减少代表流量的增加,正向边容量减少多少,正向流 量就增加多少,同时增加相应的反向容量,意思就是说反向的能允许的流量增加,而如果接下来的操作反向容量减少,也就是有反向的流量,也即是正向流量的减少,不管正向反向流量都可增可少,但是注意的是实际上最大流只会有一个方向的流量,但是可以等效为上述操作。直至所有增广路径的残余流量都是0。-------------ford——fulkerson
- push——relabel:此算法较难理解,初始化后若一个点有溢出,并且其所有能流入的点(因为在构图里面允许反向边,所以不用像算法导论里面允许一个反向的流量作为残余边 来减少流量,而本算法在对反向容量增加时可以达到同样的效果。所以只要capacity[u][v]>0就说明还有残余流量)高度均大于等于它,就对此点更新高度。若此点高度等于其能流入的点高度加1,则对此边推入操作。因为在满足溢出,可流入条件下,推入和重贴标签是互斥的,可以优化。
- 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 105
short 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;
}
#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;
}