网络流模板



Edmond Karp 算法:


#include <iostream>
#include <queue>
#include<string.h>
using namespace std;
#define arraysize 201
int maxData = 0x7fffffff;
int capacity[arraysize][arraysize]; //记录残留网络的容量
int flow[arraysize];                //标记从源点到当前节点实际还剩多少流量可用
int pre[arraysize];                 //标记在这条路径上当前节点的前驱,同时标记该节点是否在队列中
int n,m;
queue<int> myqueue;
int BFS(int src,int des)
{
    int i,j;
    while(!myqueue.empty())       //队列清空
        myqueue.pop();
    for(i=1;i<m+1;++i)
    {
        pre[i]=-1;
    }
    pre[src]=0;
    flow[src]= maxData;
    myqueue.push(src);
    while(!myqueue.empty())
    {
        int index = myqueue.front();
        myqueue.pop();
        if(index == des)            //找到了增广路径
            break;
        for(i=1;i<m+1;++i)
        {
            if(i!=src && capacity[index][i]>0 && pre[i]==-1)
            {
                 pre[i] = index; //记录前驱
                 flow[i] = min(capacity[index][i],flow[index]);   //关键:迭代的找到增量
                 myqueue.push(i);
            }
        }
    }
    if(pre[des]==-1)      //残留图中不再存在增广路径
        return -1;
    else
        return flow[des];
}
int EK(int src,int des)
{
    int increasement= 0;
    int sumflow = 0;
    while((increasement=BFS(src,des))!=-1)
    {
         int k = des;          //利用前驱寻找路径
         while(k!=src)
         {
              int last = pre[k];
              capacity[last][k] -= increasement; //改变正向边的容量
              capacity[k][last] += increasement; //改变反向边的容量
              k = last;
         }
         sumflow += increasement;
    }
    return sumflow;
}
int main()
{
    int i,j;
    int start,end,ci;
    while(cin>>n>>m)
    {
        memset(capacity,0,sizeof(capacity));
        memset(flow,0,sizeof(flow));
        for(i=0;i<n;++i)
        {
            cin>>start>>end>>ci;
            if(start == end)               //考虑起点终点相同的情况
               continue;
            capacity[start][end] +=ci;     //此处注意可能出现多条同一起点终点的情况(重边)
        }
        cout<<EK(1,m)<<endl;
    }
    return 0;
}





Dinic非递归版:


#define N 5000
#define M 1505
#define inf 536870912
//N为点数 M为边数

struct Edge{
	int from, to, cap, nex;
}edge[M*10];//注意这个一定要够大 不然会re 还有反向弧

int head[N], edgenum;
void addedge(int u, int v, int cap){
	Edge E = { u, v, cap, head[u]};
	edge[ edgenum ] = E;
	head[u] = edgenum ++;

	Edge E2= { v, u, 0,   head[v]};
	edge[ edgenum ] = E2;
	head[v] = edgenum ++;
}
int sign[N], s, t;
bool BFS(int from, int to){
	memset(sign, -1, sizeof(sign));
	sign[from] = 0;

	queue<int>q;
	q.push(from);
	while( !q.empty() ){
		int u = q.front(); q.pop();
		for(int i = head[u]; i!=-1; i = edge[i].nex)
		{
			int v = edge[i].to;
			if(sign[v]==-1 && edge[i].cap)
			{
				sign[v] = sign[u] + 1, q.push(v);
				if(sign[to] != -1)return true;
			}
		}
	}
	return false;
}
int Stack[M*4], top, cur[M*4];
int dinic(){

	int ans = 0;
	while( BFS(s, t) )
	{
		memcpy(cur, head, sizeof(head));
		int u = s;		top = 0;
		while(1)
		{
			if(u == t)
			{
				int flow = inf, loc;//loc 表示 Stack 中 cap 最小的边
				for(int i = 0; i < top; i++)
					if(flow > edge[ Stack[i] ].cap)
					{
						flow = edge[Stack[i]].cap;
						loc = i;
					}

					for(int i = 0; i < top; i++)
					{
						edge[ Stack[i] ].cap -= flow;
						edge[Stack[i]^1].cap += flow;
					}
					ans += flow;
					top = loc;
					u = edge[Stack[top]].from;
			}
			for(int i = cur[u]; i!=-1; cur[u] = i = edge[i].nex)//cur[u] 表示u所在能增广的边的下标
				if(edge[i].cap && (sign[u] + 1 == sign[ edge[i].to ]))break;
			if(cur[u] != -1)
			{
				Stack[top++] = cur[u];
				u = edge[ cur[u] ].to;
			}
			else
			{
				if( top == 0 )break;
				sign[u] = -1;
				u = edge[ Stack[--top] ].from;
			}
		}
	}
	return ans;
}


 


 

 

Dinic 递归版:

 


#define inf 1000000
#define N 1000 
#define M 100000
//N为点数 M为边数
inline int Min(int a,int b){return a>b?b:a;} //注意这个类型是int

struct Edge{
	int from, to, cap, nex;
}edge[M*2];//双向边,注意RE 注意这个模版是 相同起末点的边 同时有效而不是去重
int head[N],edgenum;//2个要初始化-1和0

void addedge(int u, int v, int cap){//网络流要加反向弧,即u->v 为10 则 v->u为 -10
	Edge E = {u, v, cap, head[u]};
	edge[ edgenum ] = E;
	head[ u ] = edgenum++;

	Edge E2 = {v, u, 0,  head[v]}; //这里的cap若是单向边要为0
	edge[ edgenum ] = E2;
	head[ v ] = edgenum++;
}


int dis[N], cur[N];//dis[i]表示i点距离起点的距离 cur[i]表示i点所连接的边中 正在考虑的边 优化不再考虑已经用过的点 初始化为head
bool vis[N];
bool BFS(int Start,int End){//跑一遍最短路
	memset(vis,0,sizeof(vis)); 
	memset(dis,-1,sizeof(dis));

	queue<int>Q;
	Q.push(Start);	dis[Start]=0;	vis[Start]=1;

	while(!Q.empty())
	{
		int u = Q.front(); Q.pop();
		for(int i = head[u]; i != -1; i = edge[i].nex){
			Edge E = edge[i];
			if( !vis[E.to] && E.cap > 0)
			{
				vis[ E.to ] = true;
				dis[ E.to ] = dis[ u ] + 1;
				if(E.to == End) return true;
				Q.push( E.to );
			}
		}
	}
	return false;
}
int DFS(int x, int a,int End){//当前 流入x 的流量是a   流量a 是所有流过边中 边权的最小值
	if( x == End || a == 0)return a; 
	int flow = 0, f; //flow表示从x点流到下面所有点,最大的流量
	for(int& i = cur[x]; i != -1; i = edge[i].nex)
	{
		Edge& E = edge[i];
		if(dis[x] + 1 == dis[E.to] && (f = DFS(E.to , Min(a, E.cap), End))>0 )
		{
			E.cap -= f;
			edge[ i^1 ].cap += f;//反向边要减掉
			flow += f;
			a -= f;
			if(a==0)break;
		}
	}
	return flow;
}
int Maxflow(int Start,int End){
	int flow=0; 
	while(BFS(Start,End)){ //当存在源点到汇点的路径时
		memcpy(cur,head,sizeof(head));//把head的数组复制过去
		flow += DFS(Start, inf, End);
	}
	return flow;
}


ISAP 版:



typedef  struct {
	int v, next, val;
} edge;
const int MAXN = 20010;
const int MAXM = 500010;
 
edge e[MAXM];
int p[MAXN], eid;
 
inline void init() {
	memset(p, -1, sizeof(p));
	eid = 0;
}
 
//有向
inline void insert1(int from, int to, int val) {
	e[eid].v = to;
	e[eid].val = val;
	e[eid].next = p[from];
	p[from] = eid++;
 
	swap(from, to);
 
	e[eid].v = to;
	e[eid].val = 0;
	e[eid].next = p[from];
	p[from] = eid++;
}
 
//无向
inline void insert2(int from, int to, int val) {
	e[eid].v = to;
	e[eid].val = val;
	e[eid].next = p[from];
	p[from] = eid++;
 
	swap(from, to);
 
	e[eid].v = to;
	e[eid].val = val;
	e[eid].next = p[from];
	p[from] = eid++;
}
 
int n, m; //n为点数 m为边数
int h[MAXN];
int gap[MAXN];
 
int source, sink;
inline int dfs(int pos, int cost) {
	if (pos == sink) {
		return cost;
	}
 
	int j, minh = n - 1, lv = cost, d;
 
	for (j = p[pos]; j != -1; j = e[j].next) {
		int v = e[j].v, val = e[j].val;
 
		if(val > 0) {
			if (h[v] + 1 == h[pos]) {
				if (lv < e[j].val) {
					d = lv;
				} else {
					d = e[j].val;
				}
 
				d = dfs(v, d);
				e[j].val -= d;
				e[j ^ 1].val += d;
				lv -= d;
 
				if (h[source] >= n) {
					return cost - lv;
				}
 
				if (lv == 0) {
					break;
				}
			}
 
			if (h[v] < minh)	{
				minh = h[v];
			}
		}
	}
 
	if (lv == cost) {
		--gap[h[pos]];
 
		if (gap[h[pos]] == 0) {
			h[source] = n;
		}
 
		h[pos] = minh + 1;
		++gap[h[pos]];
	}
 
	return cost - lv;
 
}
 
int sap(int st, int ed) {
 
	source = st;
	sink = ed;
	int ret = 0;
	memset(gap, 0, sizeof(gap));
	memset(h, 0, sizeof(h));
 
	//gap[st] = n;
	gap[0] = n;
 
	while (h[st] < n) {
		ret += dfs(st, INT_MAX);
	}
 
	return ret;
}


你可能感兴趣的:(网络流模板)