最大流模板
EK 算法:
邻接矩阵保存
模板题hdu3549
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<climits>
using namespace std;
#define N 16
int capacity[N][N];//容量
int flow[N];//残余流量
int pre[N];//前趋
int n, m;
queue<int> Q;
int BFS(int src, int des) {
//初始化
while (!Q.empty()) {
Q.pop();
}
for (int i = 1; i < n + 1; i++) {
pre[i] = -1;
}
pre[src] = 0;
flow[src] = INT_MAX;//初始化源点的流量为无穷大
Q.push(src);
while (!Q.empty()) {
int index = Q.front();
Q.pop();
if (index == des) {//找到了增广路径
break;
}
for (int i = 1; i < n + 1; i++) {
if (i != src && capacity[index][i] > 0 && pre[i] == -1) {
pre[i] = index;
//增广路残容流量
flow[i] = min(capacity[index][i], flow[index]);
Q.push(i);
}
}
}//while
if (pre[des] == -1) {
return -1; //残留图中不存在增广路径
} else {
return flow[des];
}
}
int MaxFlow(int src, int des) {
int aug = 0;
int sumflow = 0;
while ((aug = BFS (src, des)) != -1) {
int k = des; //利用前驱寻找路径
while (k != src) {
int last = pre[k];
capacity[last][k] -= aug;
capacity[k][last] += aug;
k = last;
}
sumflow += aug;
}
return sumflow;
}
int main() {
int cas, cases = 1;
scanf("%d", &cas);
while (cas--) {
scanf("%d%d", &n, &m);
memset(capacity, 0, sizeof(capacity));
memset(flow, 0, sizeof(flow));
for (int i = 0; i < m; i++) {
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
if (u == v) {//起点终点相同
continue;
}
capacity[u][v] += w;
}
printf("Case %d: ", cases++);
printf("%d\n", MaxFlow(1, n));
}
return 0;
}
ISAP算法
邻接表存储:
模板题hdu1532
#include<iostream>
#include<algorithm>
using namespace std;
const int NV = 210;
const int NE = 410;
int n,size,head[NV],dis[NV],gap[NV],pre[NV],cur[NV];
struct edge
{
int v,w,next;
edge(){}
edge(int v,int next,int w=0):v(v),next(next),w(w){}
}E[NE];
inline void insert(int u,int v,int w)
{
E[size]=edge(v,head[u],w);
head[u]=size++;
E[size]=edge(u,head[v],0);
head[v]=size++;
}
int ISAP(int src,int des)
{
int maxflow=0;
memset(dis,0,sizeof(dis));
memset(gap,0,sizeof(gap));
for(int i=0;i<=n;i++)
cur[i]=head[i];
int u=pre[src]=src;
int aug=-1;
while(dis[src]<n)
{
loop: for(int &i=cur[u];i!=-1;i=E[i].next)
{
int v=E[i].v;
if(E[i].w && dis[u]==dis[v]+1)
{
aug=min(aug,E[i].w);
pre[v]=u;
u=v;
if(v==des){
maxflow+=aug;
for(u=pre[u];v!=src;v=u,u=pre[u])
{
E[cur[u]].w-=aug;
E[cur[u]^1].w+=aug;
}
aug=INT_MAX;
}
goto loop;
}
}
int mdis=n;
for(int i=head[u];i!=-1;i=E[i].next)
{
int v=E[i].v;
if(E[i].w && mdis>dis[v])
{
cur[u]=i;
mdis=dis[v];
}
}
if((--gap[dis[u]])==0)
break;
gap[dis[u]=mdis+1]++;
u=pre[u];
}
return maxflow;
}
int main()
{
int m,u,v,w;
while(scanf("%d %d",&m,&n)==2)
{
memset(head,-1,sizeof(head));
size=0;
while(m--)
{
scanf("%d %d %d",&u,&v,&w);
insert(u,v,w);
}
printf("%d\n",ISAP(1,n));
}
return 0;
}
邻接矩阵存储:
View Code
此模板来自http://www.icycandy.com/blog/template-of-broaden-the-shortest-path-algorithm/comment-page-1
#include <iostream>
#include <queue>
#define msize 1024 //最大顶点数目
using namespace std;
int d[msize]; //标号
int r[msize][msize]; //残留网络,初始为原图
int num[msize]; //num[i]表示标号为i的顶点数有多少
int pre[msize];
int n,m,s,t; //m个顶点,n条边,从源点s到汇点t
void ini_d() //BFS计算标号,汇点t标号为0
{
int k;
queue<int>Q;
memset(d,1,sizeof(d));
memset(num,0,sizeof(num));
Q.push(t);
d[t]=0;
num[0]=1;
while (!Q.empty())
{
k=Q.front(),Q.pop();
for (int i=0;i<m;i++)
{
if (d[i]>=m&&r[i][k]>0)
{
d[i]=d[k]+1;
Q.push(i);
num[d[i]]++;
}
}
}
}
int findAlowArc(int i) //从i出发寻找允许弧
{
int j;
for (j=0;j<m;j++) if (r[i][j]>0&&d[i]==d[j]+1) return j;
return -1;
}
int reLable(int i) //重新标号
{
int mm=INT_MAX;
for (int j=0;j<m;j++)
if (r[i][j]>0) mm=min(mm,d[j]+1);
return mm==INT_MAX?m:mm;
}
int maxFlow(int s,int t) //从源点s出发的最大流
{
int flow=0,i=s,j;
int delta; //增量
memset(pre,-1,sizeof(pre));
while (d[s]<m)
{
j=findAlowArc(i);
if (j>=0)
{
pre[j]=i;
i=j;
if (i==t) //更新残留网络
{
delta=INT_MAX;
for (i=t;i!=s;i=pre[i]) delta=min(delta,r[pre[i]][i]);
for (i=t;i!=s;i=pre[i]) r[pre[i]][i] -= delta, r[i][pre[i]] += delta;
flow += delta;
}
}
else
{
int x=reLable(i); //重新标号
num[x]++;
num[d[i]]–;
if (num[d[i]]==0) return flow; //间隙优化
d[i]=x;
if (i!=s) i=pre[i];
}
}
return flow;
}