Edmonds-Karp算法,最大流POJ(1459)
题目链接:http://poj.org/problem?id=1459
解题报告:
电力调度站不涉及流的产生和消耗,不用考虑,Edmonds-Karp算法,就是利用剩余网络和增广路来解决,网络中的最大流。
原理:剩余网络,就是一种回退,构造完在剩余网络后,在剩余网络中找一条增广路,其中的最小流量,每个边加上这个最小流量或者减去这个最小流量,那么流就变成最大的了。
在加上或者减去这个最小流量时,初始化flow[][]这个剩余网络为0,最小流量node[v]=min(node[u],cap[u][v]-flow[u][v]),重新更新flow[][]+=node[t]后,就是真正的剩余网络了,cap[u][v]-flow[u][v]就表示的是这条边最大的流量了,这里也可以看出初始化flow[][]为0的目的了。
然后是,增广路的搜索,BFS广度优先搜索出每一条增广路,没找到一条增广路,就更新flow剩余网络,直到不存在增广路,就是说,直到原网络没有了任何的可以加上的流了。
这个题目,不能直接用传统意义上的最大流,因为这么没有一个绝对的源点和汇点,所以要建一个超级源点s,和超级汇点,n,n+1;
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <stdio.h> #include <string.h> #include <queue> #include <algorithm> #define MAX 120 using namespace std; int n; ///节点数 int np; ///发电站数 int nc; ///消费者数 int m; ///传输线数 int cap[MAX][MAX]; ///网络的邻接矩阵 int from,to,value; ///形参s是超级源点,形参t是超级汇点 int EKarp(int s,int t) { queue<int> Q; ///用于BFS的搜索队列 int flow[MAX][MAX]; ///剩余网络的邻接矩阵 int pre[MAX]; ///增广路径 int node[MAX]; ///增广路径上的最小流 int u,v; int maxflow=0; ///网络的最大流 ///剩余网络的初始化 memset(flow,0,sizeof(flow)); ///不断寻找增广路径 while(true) { Q.push(s); memset(node,0,sizeof(node)); node[s]=100000; ///最小流量初值,无穷大 ///BFS算法,搜索增广路径 while(!Q.empty()) { u=Q.front(); Q.pop(); for(v=0; v<=t; v++) { if(!node[v]&&cap[u][v]>flow[u][v]) { Q.push(v); node[v]=min(node[u],cap[u][v]-flow[u][v]); pre[v]=u; } } } ///当瓶颈容量为0时,说明不存在增广路径,搜索结束 if(node[t]==0) break; ///根据增广路径和瓶颈容量,更新剩余网络 for(u=t; u!=s; u=pre[u]) { flow[pre[u]][u]+=node[t]; flow[u][pre[u]]-=node[t]; } maxflow+=node[t]; } return maxflow; ///总流量累加 } int main() { while(scanf("%d%d%d%d",&n,&np,&nc,&m)!=EOF) { memset(cap,0,sizeof(cap)); ///读取输电线的数据 while(m--) { scanf(" (%d,%d)%d",&from,&to,&value); cap[from][to]=value; } ///读取发电站数据,构造超级源点 while(np--) { scanf(" (%d)%d",&from,&value); cap[n][from]=value; } ///读取消费者数据,构造超级汇点 while(nc--) { scanf(" (%d)%d",&from,&value); cap[from][n+1]=value; } printf("%d\n",EKarp(n,n+1)); } return 0; }